diff options
author | Bill Schwartz <whs@us.ibm.com> | 2015-09-08 15:02:45 -0500 |
---|---|---|
committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2015-09-16 11:05:54 -0500 |
commit | 52cdccf5cb1bed63f31036c79b1cb5f2c83e7220 (patch) | |
tree | e533caab69a0dc6bd61abee180541e8bc82a525a /src | |
parent | df5c383842ed36306c537b22f7ac23971ed04b1d (diff) | |
download | blackbird-hostboot-52cdccf5cb1bed63f31036c79b1cb5f2c83e7220.tar.gz blackbird-hostboot-52cdccf5cb1bed63f31036c79b1cb5f2c83e7220.zip |
WOF HWPs
Add support for UltraTurbo and related WOF Elements to Pstate
CQ:SW308304
Change-Id: I4ef70a1262c1a952a15c251371af8a1f7e8d407d
Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/19718
Reviewed-by: Thi N. Tran <thi@us.ibm.com>
Reviewed-by: William H. Schwartz <whs@us.ibm.com>
Tested-by: William H. Schwartz <whs@us.ibm.com>
Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/20373
Tested-by: Jenkins Server
Tested-by: Jenkins OP Build CI
Tested-by: FSP CI Jenkins
Tested-by: Jenkins OP HW
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/usr/hwpf/hwp/occ/occ_procedures/p8_pm_prep_for_reset.C | 406 | ||||
-rwxr-xr-x | src/usr/hwpf/hwp/pstates/pstates/gpstCheckByte.c | 13 | ||||
-rwxr-xr-x | src/usr/hwpf/hwp/pstates/pstates/lab_pstates.c | 524 | ||||
-rwxr-xr-x | src/usr/hwpf/hwp/pstates/pstates/lab_pstates.h | 21 | ||||
-rwxr-xr-x | src/usr/hwpf/hwp/pstates/pstates/p8_build_pstate_datablock.C | 3256 | ||||
-rwxr-xr-x | src/usr/hwpf/hwp/pstates/pstates/p8_build_pstate_datablock.H | 36 | ||||
-rwxr-xr-x | src/usr/hwpf/hwp/pstates/pstates/p8_build_pstate_datablock_errors.xml | 110 | ||||
-rwxr-xr-x | src/usr/hwpf/hwp/pstates/pstates/pstate_tables.c | 1003 | ||||
-rwxr-xr-x | src/usr/hwpf/hwp/pstates/pstates/pstate_tables.h | 60 | ||||
-rwxr-xr-x | src/usr/hwpf/hwp/pstates/pstates/pstates.c | 13 | ||||
-rwxr-xr-x | src/usr/hwpf/hwp/pstates/pstates/pstates.h | 337 | ||||
-rw-r--r-- | src/usr/hwpf/hwp/pstates/pstates_common.mk | 4 |
12 files changed, 3965 insertions, 1818 deletions
diff --git a/src/usr/hwpf/hwp/occ/occ_procedures/p8_pm_prep_for_reset.C b/src/usr/hwpf/hwp/occ/occ_procedures/p8_pm_prep_for_reset.C index 438ddfc4f..28575ef0f 100644 --- a/src/usr/hwpf/hwp/occ/occ_procedures/p8_pm_prep_for_reset.C +++ b/src/usr/hwpf/hwp/occ/occ_procedures/p8_pm_prep_for_reset.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2013,2014 */ +/* Contributors Listed Below - COPYRIGHT 2013,2015 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -22,7 +22,7 @@ /* permissions and limitations under the License. */ /* */ /* IBM_PROLOG_END_TAG */ -// $Id: p8_pm_prep_for_reset.C,v 1.30 2014/04/21 14:27:53 bcbrock Exp $ +// $Id: p8_pm_prep_for_reset.C,v 1.31 2015/05/13 03:12:36 stillgs Exp $ // $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/ipl/fapi/p8_pm_prep_for_reset.C,v $ //------------------------------------------------------------------------------ // *! (C) Copyright International Business Machines Corp. 2011 @@ -33,41 +33,41 @@ // *! OWNER NAME: Ralf Maier Email: ralf.maier@de.ibm.com // *! /// \file p8_pm_prep_for_reset.C -/// \brief Initialize powermanagement -/// +/// \brief Reset Power Management function +/// //------------------------------------------------------------------------------ /// /// High-level procedure flow: /// /// \verbatim -/// - call p8_pm_firinit *chiptarget, -/// - Mask the PM FIRs /// -/// - call p8_occ_control.C *chiptarget, ENUM:OCC_STOP ppc405_reset_ctrl = PPC405_RESET_SEQUENCE -/// - OCC PPC405 put into reset safely +/// do { +/// - Clear the Deep Exit Masks to allow Special Wake-up to occur +/// - Put all EX chiplets in special wakeup +/// - Mask the PM FIRs +/// - Disable PMC OCC HEARTBEAT before halting and reset OCC +/// - Halt and then Reset the PPC405 /// - PMC moves to Vsafe value due to heartbeat loss +/// - Force Vsafe value into voltage controller to cover the case that the +/// Pstate hardware didn't move correctly +/// - Reset PCBS-PM +/// - Reset PMC +/// As the PMC reset kills ALL of the configuration, the idle portion +/// must be reestablished to allow that portion to operate. +/// - Run SLW Initialiation +/// - This allows special wake-up removal before exit +/// - Reset PSS +/// - Reset GPEs +/// - Reset PBA +/// - Reset SRAM Controller +/// - Reset OCB +/// - Clear special wakeups +/// } while(0); /// -/// - call p8_cpu_special_wakeup.C *chiptarget, ENUM:OCC_SPECIAL_WAKEUP -/// - For each chiplet, put into Special Wake-up via the OCC special wake-up bit -/// -/// - call p8_pmc_force_vsafe.C *chiptarget, -/// - Forces the Vsafe value into the voltage controller -/// -/// - call p8_pcbs_init.C *chiptarget, ENUM:PCBSPM_RESET -/// -/// - call p8_pmc_init.C *chiptarget, ENUM:PMC_RESET -/// - Issue reset to the PMC -/// -/// - call p8_poregpe_init.C *chiptarget, ENUM:POREGPE_RESET -/// -/// - call p8_pba_init.C *chiptarget, ENUM:PBA_RESET -/// -/// - call p8_occ_sram_init.C *chiptarget, ENUM:OCC_SRAM_RESET -/// -/// - call p8_ocb_init .C *chiptarget, ENUM:OCC_OCB_RESET +/// if error, clear special wakeups to leave this procedure clean /// /// SLW engine reset is not done here as this will blow away all setup -/// in istep 15. Thus, ALL manipulation of this is via calls to +/// in istep 15. Thus, ALL manipulation of this is via calls to /// p8_poreslw_ioit or by p8_poreslw_recovery. /// /// \endverbatim @@ -101,12 +101,15 @@ using namespace fapi; fapi::ReturnCode special_wakeup_all (const fapi::Target &i_target, bool i_action); -// FSM trace wrapper +fapi::ReturnCode +clear_deep_exit_mask (const fapi::Target &i_target); + +// FSM trace wrapper fapi::ReturnCode p4rs_pcbs_fsm_trace (const fapi::Target& i_primary_target, - const fapi::Target& i_secondary_target, + const fapi::Target& i_secondary_target, const char * i_msg); - + // ---------------------------------------------------------------------- // Function definitions // ---------------------------------------------------------------------- @@ -138,11 +141,11 @@ p8_pm_prep_for_reset( const fapi::Target &i_primary_chip_target, uint32_t e_rc = 0; std::vector<fapi::Target> l_exChiplets; ecmdDataBufferBase data(64); - ecmdDataBufferBase mask(64); + ecmdDataBufferBase mask(64); uint64_t address = 0; const char * PM_MODE_NAME_VAR; // Defines storage for PM_MODE_NAME - + bool b_special_wakeup_pri = false; bool b_special_wakeup_sec = false; @@ -160,7 +163,7 @@ p8_pm_prep_for_reset( const fapi::Target &i_primary_chip_target, FAPI_ERR("fapiGetAttribute of ATTR_IS_MPIPL rc = 0x%x", (uint32_t)rc); break; } - + FAPI_INF("IPL mode = %s", ipl_mode ? "MPIPL" : "NORMAL"); @@ -195,58 +198,84 @@ p8_pm_prep_for_reset( const fapi::Target &i_primary_chip_target, { FAPI_INF("Running on DCM"); } + + // ****************************************************************** + // Clear the Deep Exit Masks to allow Special Wake-up to occur + // ****************************************************************** + // Primary + rc = clear_deep_exit_mask(i_primary_chip_target); + if (rc) + { + FAPI_ERR("clear_deep_exit_mask: Failed for Primary Target %s", + i_primary_chip_target.toEcmdString()); + break; + } + + // Secondary + if ( i_secondary_chip_target.getType() != TARGET_TYPE_NONE ) + { + rc = clear_deep_exit_mask(i_secondary_chip_target); + if (rc) + { + FAPI_ERR("clear_deep_exit_mask: Failed for Secondary Target %s", + i_secondary_chip_target.toEcmdString()); + break; + } + } + + // ****************************************************************** // FSM trace // ****************************************************************** rc = p4rs_pcbs_fsm_trace (i_primary_chip_target, i_secondary_chip_target, "start of prep for reset"); - if (!rc.ok()) + if (!rc.ok()) { break; } - + // ****************************************************************** - // Put all EX chiplets in special wakeup + // Put all EX chiplets in special wakeup // ***************************************************************** // This is done before FIR masking to ensure that idle functions // are properly monitored - + // Primary rc = special_wakeup_all (i_primary_chip_target, true); if (rc) { - FAPI_ERR("special_wakeup_all - Enable: Failed for Target %s", + FAPI_ERR("special_wakeup_all - Enable: Failed for Target %s", i_primary_chip_target.toEcmdString()); break; - } + } b_special_wakeup_pri = true; - + rc = p8_pm_glob_fir_trace (i_primary_chip_target, "after SPWKUP"); - if (!rc.ok()) { break; } - + if (!rc.ok()) { break; } + // Secondary if ( i_secondary_chip_target.getType() != TARGET_TYPE_NONE ) { rc = special_wakeup_all (i_secondary_chip_target, true); if (rc) { - FAPI_ERR("special_wakeup_all - Enable: Failed for Target %s", + FAPI_ERR("special_wakeup_all - Enable: Failed for Target %s", i_secondary_chip_target.toEcmdString()); break; } - b_special_wakeup_sec = true; - + b_special_wakeup_sec = true; + rc = p8_pm_glob_fir_trace (i_secondary_chip_target, "after SPWKUP"); - if (!rc.ok()) { break; } - - } - + if (!rc.ok()) { break; } + + } + // ****************************************************************** // FSM trace // ****************************************************************** - rc = p4rs_pcbs_fsm_trace (i_primary_chip_target, i_secondary_chip_target, + rc = p4rs_pcbs_fsm_trace (i_primary_chip_target, i_secondary_chip_target, "after special wake-up setting"); - if (!rc.ok()) + if (!rc.ok()) { break; } @@ -264,8 +293,8 @@ p8_pm_prep_for_reset( const fapi::Target &i_primary_chip_target, } rc = p8_pm_glob_fir_trace (i_primary_chip_target, "after Masking"); - if (!rc.ok()) { break; } - + if (!rc.ok()) { break; } + if ( i_secondary_chip_target.getType() != TARGET_TYPE_NONE ) { @@ -275,24 +304,24 @@ p8_pm_prep_for_reset( const fapi::Target &i_primary_chip_target, FAPI_ERR("ERROR: p8_pm_firinit detected failed result"); break; } - + rc = p8_pm_glob_fir_trace (i_secondary_chip_target, "after Masking"); - if (!rc.ok()) { break; } + if (!rc.ok()) { break; } } - + // ****************************************************************** // FSM trace // ****************************************************************** - rc = p4rs_pcbs_fsm_trace (i_primary_chip_target, i_secondary_chip_target, + rc = p4rs_pcbs_fsm_trace (i_primary_chip_target, i_secondary_chip_target, "after FIR masking"); - if (!rc.ok()) + if (!rc.ok()) { break; } // ****************************************************************** // Disable PMC OCC HEARTBEAT before reset OCC - // ****************************************************************** + // ****************************************************************** // Primary rc = fapiGetScom(i_primary_chip_target, PMC_OCC_HEARTBEAT_REG_0x00062066 , data ); if (rc) @@ -344,7 +373,7 @@ p8_pm_prep_for_reset( const fapi::Target &i_primary_chip_target, // ****************************************************************** // Put OCC PPC405 into reset safely - // ****************************************************************** + // ****************************************************************** FAPI_INF("Put OCC PPC405 into reset safely"); FAPI_DBG("Executing: p8_occ_control.C"); @@ -364,28 +393,28 @@ p8_pm_prep_for_reset( const fapi::Target &i_primary_chip_target, break; } } - + // ****************************************************************** // FSM trace // ****************************************************************** - rc = p4rs_pcbs_fsm_trace (i_primary_chip_target, i_secondary_chip_target, + rc = p4rs_pcbs_fsm_trace (i_primary_chip_target, i_secondary_chip_target, "after OCC Reset"); - if (!rc.ok()) + if (!rc.ok()) { break; } - + // Check for xstops and recoverables rc = p8_pm_glob_fir_trace (i_primary_chip_target, "after OCC Reset"); - if (!rc.ok()) { break; } - + if (!rc.ok()) { break; } + if ( i_secondary_chip_target.getType() != TARGET_TYPE_NONE ) - { + { rc = p8_pm_glob_fir_trace (i_secondary_chip_target, "after OCC Reset"); - if (!rc.ok()) { break; } + if (!rc.ok()) { break; } } - + // ****************************************************************** // Force Vsafe value into voltage controller // ****************************************************************** @@ -400,7 +429,7 @@ p8_pm_prep_for_reset( const fapi::Target &i_primary_chip_target, FAPI_ERR("Failed to force Vsafe value into voltage controller. With rc = 0x%x", (uint32_t)rc); break; } - + // Secondary // Primary passed in for FFDC reasons upon error if ( i_secondary_chip_target.getType() != TARGET_TYPE_NONE ) @@ -410,31 +439,31 @@ p8_pm_prep_for_reset( const fapi::Target &i_primary_chip_target, { FAPI_ERR("Failed to force Vsafe value into voltage controller. With rc = 0x%x", (uint32_t)rc); break; - } + } } - + // ****************************************************************** // FSM trace // ****************************************************************** - rc = p4rs_pcbs_fsm_trace (i_primary_chip_target, i_secondary_chip_target, + rc = p4rs_pcbs_fsm_trace (i_primary_chip_target, i_secondary_chip_target, "after force Vsafe"); - if (!rc.ok()) + if (!rc.ok()) { break; } - + // Check for xstops and recoverables rc = p8_pm_glob_fir_trace (i_primary_chip_target, "after Force Vsafe"); - if (!rc.ok()) { break; } - + if (!rc.ok()) { break; } + if ( i_secondary_chip_target.getType() != TARGET_TYPE_NONE ) - { + { rc = p8_pm_glob_fir_trace (i_secondary_chip_target, "after Force Vsafe"); - if (!rc.ok()) { break; } - } - + if (!rc.ok()) { break; } + } + // ****************************************************************** - // Prepare PCBSLV_PM for RESET + // Prepare PCBS_PM for RESET // ****************************************************************** // - p8_pcbs_init internally loops over all enabled chiplets FAPI_INF("Prepare PCBSLV_PM for RESET"); @@ -454,7 +483,7 @@ p8_pm_prep_for_reset( const fapi::Target &i_primary_chip_target, { FAPI_INF("Recoverable attention is **ACTIVE** in prep_for_reset after PCBS reset"); } - + // Secondary if ( i_secondary_chip_target.getType() != TARGET_TYPE_NONE ) { @@ -465,32 +494,32 @@ p8_pm_prep_for_reset( const fapi::Target &i_primary_chip_target, FAPI_ERR("p8_pcbs_init: Failed to prepare PCBSLV_PM for RESET. With rc = 0x%x", (uint32_t)rc); break; } - + GETSCOM(rc, i_secondary_chip_target, address, data); if (data.getNumBitsSet(0,64)) { FAPI_INF("Recoverable attention is **ACTIVE** in prep_for_reset after PCBS reset"); } } - + // ****************************************************************** // FSM trace // ****************************************************************** rc = p4rs_pcbs_fsm_trace (i_primary_chip_target, i_secondary_chip_target, "after PCBS reset"); - if (!rc.ok()) + if (!rc.ok()) { break; } - + // Check for xstops and recoverables rc = p8_pm_glob_fir_trace (i_primary_chip_target, "after PCBS reset"); - if (!rc.ok()) { break; } - + if (!rc.ok()) { break; } + if ( i_secondary_chip_target.getType() != TARGET_TYPE_NONE ) - { + { rc = p8_pm_glob_fir_trace (i_secondary_chip_target, "after PCBS reset"); - if (!rc.ok()) { break; } - } + if (!rc.ok()) { break; } + } // ****************************************************************** // Reset PMC @@ -504,21 +533,21 @@ p8_pm_prep_for_reset( const fapi::Target &i_primary_chip_target, FAPI_ERR("p8_pmc_init: Failed to issue PMC reset. With rc = 0x%x", (uint32_t)rc); break; } - + // ****************************************************************** // FSM trace // ****************************************************************** - rc = p4rs_pcbs_fsm_trace (i_primary_chip_target, i_secondary_chip_target, + rc = p4rs_pcbs_fsm_trace (i_primary_chip_target, i_secondary_chip_target, "after PMC reset"); - if (!rc.ok()) + if (!rc.ok()) { break; } - + // ****************************************************************** // As the PMC reset kills ALL of the configuration, the idle portion - // must be reestablished to allow that portion to operate. This is - // what p8_poreslw_init -init does. Additionally, this lets us drop + // must be reestablished to allow that portion to operate. This is + // what p8_poreslw_init -init does. Additionally, this lets us drop // special wake-up before exiting. // ****************************************************************** // - call p8_poreslw_init.C *chiptarget, ENUM:PM_INIT @@ -526,7 +555,7 @@ p8_pm_prep_for_reset( const fapi::Target &i_primary_chip_target, FAPI_INF("Re-establish PMC Idle configuration"); FAPI_DBG("Executing: p8_poreslw_init in mode %s", PM_MODE_NAME(PM_INIT_PMC)); - + // Primary FAPI_EXEC_HWP(rc, p8_poreslw_init, i_primary_chip_target, PM_INIT_PMC); if (rc) @@ -546,17 +575,17 @@ p8_pm_prep_for_reset( const fapi::Target &i_primary_chip_target, break; } } - + // Check for xstops and recoverables rc = p8_pm_glob_fir_trace (i_primary_chip_target, "after PMC and SLW reinit"); - if (!rc.ok()) { break; } - + if (!rc.ok()) { break; } + if ( i_secondary_chip_target.getType() != TARGET_TYPE_NONE ) - { + { rc = p8_pm_glob_fir_trace (i_secondary_chip_target, "after PMC and SLW reinit"); - if (!rc.ok()) { break; } - } - + if (!rc.ok()) { break; } + } + // ****************************************************************** // Issue reset to PSS macro // ****************************************************************** @@ -584,7 +613,7 @@ p8_pm_prep_for_reset( const fapi::Target &i_primary_chip_target, break; } } - + // ****************************************************************** // Issue reset to PORE General Purpose Engine // ****************************************************************** @@ -637,13 +666,13 @@ p8_pm_prep_for_reset( const fapi::Target &i_primary_chip_target, } // Check for xstops and recoverables rc = p8_pm_glob_fir_trace (i_primary_chip_target, "after PBA reset"); - if (!rc.ok()) { break; } - + if (!rc.ok()) { break; } + if ( i_secondary_chip_target.getType() != TARGET_TYPE_NONE ) - { + { rc = p8_pm_glob_fir_trace (i_secondary_chip_target, "after PBA reset"); - if (!rc.ok()) { break; } - } + if (!rc.ok()) { break; } + } // ****************************************************************** // Issue reset to OCC-SRAM @@ -695,30 +724,30 @@ p8_pm_prep_for_reset( const fapi::Target &i_primary_chip_target, break; } } - + // Check for xstops and recoverables rc = p8_pm_glob_fir_trace (i_primary_chip_target, "after OCB reset"); - if (!rc.ok()) { break; } - + if (!rc.ok()) { break; } + if ( i_secondary_chip_target.getType() != TARGET_TYPE_NONE ) - { + { rc = p8_pm_glob_fir_trace (i_secondary_chip_target, "after OCB reset"); - if (!rc.ok()) { break; } - } + if (!rc.ok()) { break; } + } // ****************************************************************** // Remove the EX chiplet special wakeups // ***************************************************************** - + // Primary rc = special_wakeup_all (i_primary_chip_target, false); if (rc) { - FAPI_ERR("special_wakeup_all - Disable: Failed for Target %s", + FAPI_ERR("special_wakeup_all - Disable: Failed for Target %s", i_primary_chip_target.toEcmdString()); break; } b_special_wakeup_pri = false; - + // Secondary if ( i_secondary_chip_target.getType() != TARGET_TYPE_NONE ) @@ -726,38 +755,38 @@ p8_pm_prep_for_reset( const fapi::Target &i_primary_chip_target, rc = special_wakeup_all (i_secondary_chip_target, false); if (rc) { - FAPI_ERR("special_wakeup_all - Disable: Failed for Target %s", + FAPI_ERR("special_wakeup_all - Disable: Failed for Target %s", i_secondary_chip_target.toEcmdString()); break; } - + b_special_wakeup_sec = false; } - - + + // ****************************************************************** // FSM trace // ****************************************************************** - rc = p4rs_pcbs_fsm_trace (i_primary_chip_target, i_secondary_chip_target, + rc = p4rs_pcbs_fsm_trace (i_primary_chip_target, i_secondary_chip_target, "after special wake-up clearing"); - if (!rc.ok()) + if (!rc.ok()) { break; } - + // Check for xstops and recoverables rc = p8_pm_glob_fir_trace (i_primary_chip_target, "after special wake-up clearing"); - if (!rc.ok()) { break; } - + if (!rc.ok()) { break; } + if ( i_secondary_chip_target.getType() != TARGET_TYPE_NONE ) - { + { rc = p8_pm_glob_fir_trace (i_secondary_chip_target, "after special wake-up clearing"); - if (!rc.ok()) { break; } - } - + if (!rc.ok()) { break; } + } + } while(0); - - + + // Clear special wakeups that might have been set before a subsequent // error occured. Only attempts them on targets that have the boolean // flag set that they were successfully put into special wakeup. @@ -765,9 +794,9 @@ p8_pm_prep_for_reset( const fapi::Target &i_primary_chip_target, { // Save the original RC rc_hold = rc; - + do - { + { // Primary if (b_special_wakeup_pri) { @@ -775,9 +804,9 @@ p8_pm_prep_for_reset( const fapi::Target &i_primary_chip_target, rc = special_wakeup_all (i_primary_chip_target, false); if (rc) { - FAPI_ERR("special_wakeup_all - Disable: Failed during cleanup from a previous error for Target %s", + FAPI_ERR("special_wakeup_all - Disable: Failed during cleanup from a previous error for Target %s", i_primary_chip_target.toEcmdString()); - FAPI_ERR("special_wakeup_all - Disable: The original error is being returned"); + FAPI_ERR("special_wakeup_all - Disable: The original error is being returned"); fapiLogError(rc, fapi::FAPI_ERRL_SEV_RECOVERED); break; } @@ -789,7 +818,7 @@ p8_pm_prep_for_reset( const fapi::Target &i_primary_chip_target, rc = special_wakeup_all (i_secondary_chip_target, false); if (rc) { - FAPI_ERR("special_wakeup_all - Disable: Failed during cleanup from a previous error for Target %s", + FAPI_ERR("special_wakeup_all - Disable: Failed during cleanup from a previous error for Target %s", i_primary_chip_target.toEcmdString()); FAPI_ERR("special_wakeup_all - Disable: The original error is being returned"); fapiLogError(rc, fapi::FAPI_ERRL_SEV_RECOVERED); @@ -797,7 +826,7 @@ p8_pm_prep_for_reset( const fapi::Target &i_primary_chip_target, } } } while(0); - + // Restore the original RC rc = rc_hold; } @@ -808,7 +837,7 @@ p8_pm_prep_for_reset( const fapi::Target &i_primary_chip_target, } // Procedure /** - * special_wakeup_all - Sets or clears special wake-up on all configured EX on a + * special_wakeup_all - Sets or clears special wake-up on all configured EX on a * target * * @param[in] i_target Chip target w @@ -820,13 +849,13 @@ p8_pm_prep_for_reset( const fapi::Target &i_primary_chip_target, fapi::ReturnCode special_wakeup_all (const fapi::Target &i_target, bool i_action) { - fapi::ReturnCode rc; + fapi::ReturnCode rc; std::vector<fapi::Target> l_exChiplets; - uint8_t l_ex_number = 0; - + uint8_t l_ex_number = 0; + do - { - + { + rc = fapiGetChildChiplets ( i_target, TARGET_TYPE_EX_CHIPLET, l_exChiplets, @@ -836,15 +865,15 @@ special_wakeup_all (const fapi::Target &i_target, bool i_action) FAPI_ERR("Error from fapiGetChildChiplets!"); break; } - + // Iterate through the returned chiplets for (uint8_t j=0; j < l_exChiplets.size(); j++) { - - FAPI_INF("\t%s special wake-up on %s", - i_action ? "Setting" : "Clearing", + + FAPI_INF("\t%s special wake-up on %s", + i_action ? "Setting" : "Clearing", l_exChiplets[j].toEcmdString()); - + // Build the SCOM address rc = FAPI_ATTR_GET(ATTR_CHIP_UNIT_POS, &l_exChiplets[j], l_ex_number); FAPI_DBG("Running special wakeup on ex chiplet %d ", l_ex_number); @@ -853,7 +882,7 @@ special_wakeup_all (const fapi::Target &i_target, bool i_action) rc = fapiSpecialWakeup(l_exChiplets[j], i_action); if (rc) { - FAPI_ERR("fapiSpecialWakeup: Failed to put CORE %d into special wakeup. With rc = 0x%x", + FAPI_ERR("fapiSpecialWakeup: Failed to put CORE %d into special wakeup. With rc = 0x%x", l_ex_number, (uint32_t)rc); break; } @@ -863,13 +892,68 @@ special_wakeup_all (const fapi::Target &i_target, bool i_action) // Exit if error if (!rc.ok()) { + + break; + } + + } while(0); + return rc; +} + +/** + * clear deep exit mask + * + * @param[in] i_target Chip target w + * + * @retval ECMD_SUCCESS + * @retval ERROR defined in xml + */ +fapi::ReturnCode +clear_deep_exit_mask (const fapi::Target &i_target) +{ + fapi::ReturnCode rc; + ecmdDataBufferBase data(64); + + do + { + + FAPI_INF("Clearing PMC Deep Exit Mask"); + + // Read the present values for debug + rc = fapiGetScom(i_target, PMC_DEEPEXIT_MASK_0x00062092, data); + if(!rc.ok()) + { + FAPI_ERR("Scom error reading PMC_DEEPEXIT_MASK_0x00062092"); + break; + } + + FAPI_INF("PMC Deep Exit Mask value before clearing: 0x%16llX", + data.getDoubleWord(0)); + + // Clear the PMC Deep Exit Mask + data.flushTo0(); + rc = fapiPutScom(i_target, PMC_DEEPEXIT_MASK_0x00062092, data); + if(!rc.ok()) + { + FAPI_ERR("Scom error reading PMC_DEEPEXIT_MASK_0x00062092"); + break; + } + + rc = fapiGetScom(i_target, PMC_DEEPEXIT_MASK_0x00062092, data); + if(!rc.ok()) + { + FAPI_ERR("Scom error reading PMC_DEEPEXIT_MASK_0x00062092"); break; } + FAPI_INF("PMC Deep Exit Mask value after clearing: 0x%16llX", + data.getDoubleWord(0)); + } while(0); return rc; } + //------------------------------------------------------------------------------ /** * Trace PCBS FSMs across primary and secondary chips @@ -882,32 +966,32 @@ special_wakeup_all (const fapi::Target &i_target, bool i_action) */ fapi::ReturnCode p4rs_pcbs_fsm_trace(const fapi::Target& i_primary_target, - const fapi::Target& i_secondary_target, + const fapi::Target& i_secondary_target, const char * i_msg) { fapi::ReturnCode rc; do { - + rc = p8_pm_pcbs_fsm_trace_chip (i_primary_target, i_msg); if (rc) { - FAPI_ERR("pcbs_fsm_trace_chip failed for Target %s", + FAPI_ERR("pcbs_fsm_trace_chip failed for Target %s", i_primary_target.toEcmdString()); break; - } + } if ( i_secondary_target.getType() != TARGET_TYPE_NONE ) { rc = p8_pm_pcbs_fsm_trace_chip (i_secondary_target, i_msg); if (rc) { - FAPI_ERR("pcbs_fsm_trace_chip failed for Target %s", + FAPI_ERR("pcbs_fsm_trace_chip failed for Target %s", i_secondary_target.toEcmdString()); break; - } - } + } + } } while(0); return rc; } diff --git a/src/usr/hwpf/hwp/pstates/pstates/gpstCheckByte.c b/src/usr/hwpf/hwp/pstates/pstates/gpstCheckByte.c index e6d7df2e0..88d136bdf 100755 --- a/src/usr/hwpf/hwp/pstates/pstates/gpstCheckByte.c +++ b/src/usr/hwpf/hwp/pstates/pstates/gpstCheckByte.c @@ -5,7 +5,9 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* COPYRIGHT International Business Machines Corp. 2013,2014 */ +/* Contributors Listed Below - COPYRIGHT 2013,2015 */ +/* [+] International Business Machines Corp. */ +/* */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ /* you may not use this file except in compliance with the License. */ @@ -20,11 +22,15 @@ /* permissions and limitations under the License. */ /* */ /* IBM_PROLOG_END_TAG */ -// $Id: gpstCheckByte.c,v 1.1 2012/10/16 16:30:15 jimyac Exp $ +// $Id: gpstCheckByte.c,v 1.3 2015/06/01 19:02:17 stillgs Exp $ /// \file gpamCheckByte.c /// \brief Generate Pstate table check byte - Generated by genGpstCheckByte.tcl +#ifdef __cplusplus +extern "C" { +#endif + #include <stdint.h> #define BIT(x, n) (((x) >> (63 - (n))) & 1) @@ -227,3 +233,6 @@ gpstCheckByte(uint64_t gpstEntry) (cb[7] << 0); } +#ifdef __cplusplus +} // end extern C +#endif diff --git a/src/usr/hwpf/hwp/pstates/pstates/lab_pstates.c b/src/usr/hwpf/hwp/pstates/pstates/lab_pstates.c index f38a3c539..a53ca86e6 100755 --- a/src/usr/hwpf/hwp/pstates/pstates/lab_pstates.c +++ b/src/usr/hwpf/hwp/pstates/pstates/lab_pstates.c @@ -22,7 +22,7 @@ /* permissions and limitations under the License. */ /* */ /* IBM_PROLOG_END_TAG */ -// $Id: lab_pstates.c,v 1.10 2015/03/12 18:06:46 stillgs Exp $ +// $Id: lab_pstates.c,v 1.12 2015/06/01 19:02:17 stillgs Exp $ /// \file lab_pstates.c /// \brief Lab-only (as opposed to product-procedure) support for Pstates. @@ -30,6 +30,10 @@ /// Lab-only Pstate support is separated from generic Pstate support to reduce /// the size of OCC product firmware images. +#ifdef __cplusplus +extern "C" { +#endif + #include "ssx.h" // jwy #include "ppc32.h" #include "lab_pstates.h" @@ -52,7 +56,7 @@ /// \bug Confirm if the 1.6125V offset is still valid for PgP // Recall that VRM11 is inverted; rounding a VID code up rounds down the -// voltage. +// voltage. int vuv2vrm11(uint32_t v_uv, int round, uint8_t *vrm11_vid) @@ -95,7 +99,7 @@ vrm112vuv(uint8_t vrm11_vid, uint32_t *v_uv) /// \retval 0 Success /// /// \retval -IVID_INVALID_VOLTAGE If \a v_uv can not be converted to a legal -/// IVID encoding. +/// IVID encoding. int vuv2ivid(uint32_t v_uv, int round, uint8_t *ivid) @@ -109,7 +113,7 @@ vuv2ivid(uint32_t v_uv, int round, uint8_t *ivid) if (((offset % IVID_STEP_UV) != 0) && (round >= 0)) { vid++; } - + *ivid = vid; if ((vid < 0) || (vid > 0x7f)) { rc = -IVID_INVALID_VOLTAGE; @@ -118,7 +122,7 @@ vuv2ivid(uint32_t v_uv, int round, uint8_t *ivid) } return rc; } - + /// Convert an iVID code to a voltage in microvolts int @@ -132,6 +136,15 @@ ivid2vuv(uint8_t ivid, uint32_t *v_uv) } } +/// Convert a VPD current (in 0.5A units) to milliamps + +int +vpdcur2ima(uint16_t i_vpdcur, uint32_t *i_ma) +{ + *i_ma = (i_vpdcur * 1000 / 2); + return 0; +} + /// Format a voltage in microvolts as 10 microvolts into a user-supplied /// string.. The string \a s must be able to store at least /// FORMAT_10UV_STRLEN characters. @@ -142,6 +155,17 @@ sprintf_10uv(char *s, uint32_t v_uv) return sprintf(s, "%d.%05d", v_uv / 1000000, (v_uv % 1000000) / 10); } +/// Format a current in milliamps into a user-supplied +/// string.. The string \a s must be able to store at least +/// FORMAT_IMA_STRLEN characters. + +int +sprintf_ima(char *s, uint32_t i_ma) +{ + return sprintf(s, "%d.%03d", i_ma / 1000, i_ma % 1000); +} + + #ifdef FAPIECMD /// Format a voltage in microvolts as 10 microvolts to a stream. @@ -225,10 +249,40 @@ fprintf_ivid(FILE *stream, uint8_t ivid) return rc; } +/// Format a VPD current code as .5A into a user-supplied string. The +/// string \a s must be able to store at least FORMAT_0P5A_STRLEN characters. + +int +sprintf_vpd_current(char *s, uint16_t current) +{ + int rc; + uint32_t i_ma; + + if ((rc = vpdcur2ima(current, &i_ma)) != 0) { + return rc; + } + return sprintf_ima(s, i_ma); +} + + +int +fprintf_vpd_current(FILE *stream, uint16_t current) +{ + int rc; + char s[FORMAT_IMA_STRLEN]; + + rc = sprintf_vpd_current(s, current); + if (rc > 0) { + rc = fputs(s, stream); + } + return rc; +} + + // NB: The gpst_print() routine only needs the revle* functions when compiled // into little-endian Linux applications, which must provide their -// implementations. +// implementations. #ifdef _BIG_ENDIAN @@ -261,7 +315,7 @@ gpst_print(FILE *stream, GlobalPstateTable *gpst) uint8_t entries, pstate_stepsize, vrm_stepdelay_range, vrm_stepdelay_value; // Pstate pmin, pvsafe, psafe; Pstate pvsafe, psafe; - + // Endian-corrected vector Pstate fields @@ -279,7 +333,13 @@ gpst_print(FILE *stream, GlobalPstateTable *gpst) char evid_vcs_eff_str[FORMAT_10UV_STRLEN]; char maxreg_vdd_str[FORMAT_10UV_STRLEN]; char maxreg_vcs_str[FORMAT_10UV_STRLEN]; + char* ivrm_max_ps_str; + char* ultraturbo_ps_str; + char* turbo_ps_str; + char* nominal_ps_str; + char* powersave_ps_str; + // Get endian-corrected scalars options = revle32(gpst->options.options); @@ -294,11 +354,11 @@ gpst_print(FILE *stream, GlobalPstateTable *gpst) psafe = gpst->psafe; - fprintf(stream, - "---------------------------------------------------------------------------------------------------------\n"); + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\n"); fprintf(stream, "Global Pstate Table @ %p\n", gpst); - fprintf(stream, - "---------------------------------------------------------------------------------------------------------\n"); + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\n"); fprintf(stream, "%d Entries from %+d to %+d\n", entries, gpst_pmin(gpst), gpst_pmax(gpst)); fprintf(stream, "Frequency Step = %u KHz\n", frequency_step_khz); @@ -320,6 +380,10 @@ gpst_print(FILE *stream, GlobalPstateTable *gpst) pstate_stepsize, vrm_stepdelay_range, vrm_stepdelay_value); fprintf(stream, "Pvsafe %d, Psafe %d\n", pvsafe, psafe); + fprintf(stream, "iVRM Maximum Pstate %d, Number of GPST entries (from Psafe) where iVRMs are enabled: %d\n", + gpst->ivrm_max_ps, gpst->ivrm_entries); + + if (options == 0) { fprintf(stream, "No Options\n"); } else { @@ -339,17 +403,20 @@ gpst_print(FILE *stream, GlobalPstateTable *gpst) if (options & PSTATE_FORCE_INITIAL_PMIN) { fprintf(stream, " PSTATE_FORCE_INITIAL_PMIN\n"); } + if (options & PSTATE_IDDQ_0P80V_VALID) { + fprintf(stream, " PSTATE_IDDQ_0P80V_VALID\n"); + } } - fprintf(stream, - "---------------------------------------------------------------------------------------------------------\n"); - fprintf(stream, + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\n"); + fprintf(stream, " I Pstate F(MHz) evid_vdd(V) evid_vcs(V) evid_vdd_eff(V) evid_vcs_eff(V) maxreg_vdd(V) maxreg_vcs(V)\n" "---------------------------------------------------------------------------------------------------------\n"); for (i = gpst->entries - 1; i >= 0; i--) { entry.value = revle64(gpst->pstate[i].value); - + evid_vdd = entry.fields.evid_vdd; sprintf_vrm11(evid_vdd_str, evid_vdd); @@ -369,8 +436,28 @@ gpst_print(FILE *stream, GlobalPstateTable *gpst) sprintf_ivid(maxreg_vcs_str, maxreg_vcs); pstate = gpst_pmin(gpst) + i; - - fprintf(stream, + + ultraturbo_ps_str = ""; + if (pstate == 0 && gpst->turbo_ps != 0) + ultraturbo_ps_str = " <--- UltraTurbo"; + + turbo_ps_str = ""; + if (pstate == gpst->turbo_ps) + turbo_ps_str = " <--- Turbo"; + + nominal_ps_str = ""; + if (pstate == gpst->nominal_ps) + nominal_ps_str = " <--- Nominal"; + + powersave_ps_str = ""; + if (pstate == gpst->powersave_ps) + powersave_ps_str = " <--- PowerSave"; + + ivrm_max_ps_str = ""; + if (pstate == gpst->ivrm_max_ps) + ivrm_max_ps_str = " <--- iVRM Maximum"; + + fprintf(stream, "%3d %+4d " "%4d " "0x%02x %s " @@ -378,7 +465,8 @@ gpst_print(FILE *stream, GlobalPstateTable *gpst) "0x%02x %s " "0x%02x %s " "0x%02x %s " - "0x%02x %s\n", + "0x%02x %s " + "%s%s%s%s%s\n", i, pstate, (pstate0_frequency_khz + (frequency_step_khz * pstate)) / 1000, evid_vdd, evid_vdd_str, @@ -386,10 +474,15 @@ gpst_print(FILE *stream, GlobalPstateTable *gpst) evid_vdd_eff, evid_vdd_eff_str, evid_vcs_eff, evid_vcs_eff_str, maxreg_vdd, maxreg_vdd_str, - maxreg_vcs, maxreg_vcs_str); + maxreg_vcs, maxreg_vcs_str, + ultraturbo_ps_str, + turbo_ps_str, + nominal_ps_str, + powersave_ps_str, + ivrm_max_ps_str); } - fprintf(stream, - "---------------------------------------------------------------------------------------------------------\n"); + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\n"); } @@ -408,37 +501,37 @@ lpsa_print(FILE* stream, LocalPstateArray* lpsa) uint8_t entries; uint8_t entries_div4; char ivid_vdd_str[FORMAT_10UV_STRLEN]; - char ivid_vcs_str[FORMAT_10UV_STRLEN]; + char ivid_vcs_str[FORMAT_10UV_STRLEN]; uint8_t ivid_vdd, ivid_vcs; lpst_entry_t lpst_entry; vdsvin_entry_t vdsvin_entry; - fprintf(stream, - "---------------------------------------------------------------------------------------------------------\n"); + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\n"); fprintf(stream, "Local Pstate Array @ %p\n", lpsa); - fprintf(stream, - "---------------------------------------------------------------------------------------------------------\n"); + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\n"); fprintf(stream, "%d Entries from %+d to %+d\n", lpsa->entries, lpst_pmin(lpsa), lpst_pmax(lpsa)); fprintf(stream, "Step Delay Rising %u, Step Delay Falling %u\n", lpsa->stepdelay_rising, lpsa->stepdelay_lowering); - fprintf(stream, - "---------------------------------------------------------------------------------------------------------------------\n"); - fprintf(stream, + fprintf(stream, + "---------------------------------------------------------------------------------------------------------------------\n"); + fprintf(stream, " I ivid_vdd(V) ivid_vcs(V) Core vdd Core vcs ECO vdd ECO vcs ps1 inc ps2 inc ps3 inc inc step dec step\n" " pwrratio pwrratio pwrratio pwrratio \n" "---------------------------------------------------------------------------------------------------------------------\n"); - + entries = lpsa->entries; - entries_div4 = entries/4; - + entries_div4 = entries/4; + if ( entries % 4 != 0) entries_div4++; - - for (i = entries_div4-1 ; i >= 0; i--) { + + for (i = entries_div4-1 ; i >= 0; i--) { lpst_entry.value = revle64(lpsa->pstate[i].value); - + ivid_vdd = lpst_entry.fields.ivid_vdd; sprintf_ivid(ivid_vdd_str, ivid_vdd); @@ -466,20 +559,20 @@ lpsa_print(FILE* stream, LocalPstateArray* lpsa) (uint8_t)lpst_entry.fields.dec_step); } - fprintf(stream, - "---------------------------------------------------------------------------------------------------------------------\n\n"); + fprintf(stream, + "---------------------------------------------------------------------------------------------------------------------\n\n"); - fprintf(stream, + fprintf(stream, "--------------------------------\n"); - fprintf(stream, - "VDS\n"); - fprintf(stream, + fprintf(stream, + "VDS\n"); + fprintf(stream, " I beg_offset end_offset \n" - "--------------------------------\n"); + "--------------------------------\n"); - for (i = 15 ; i >= 0; i--) { + for (i = 15 ; i >= 0; i--) { vdsvin_entry.value = revle64(lpsa->vdsvin[i].value); - + fprintf(stream, "%2u " "%-10u " @@ -489,38 +582,38 @@ lpsa_print(FILE* stream, LocalPstateArray* lpsa) (uint8_t)vdsvin_entry.fields.ivid1); } - fprintf(stream, - "--------------------------------\n\n"); - + fprintf(stream, + "--------------------------------\n\n"); + - fprintf(stream, + fprintf(stream, "-----------------------------------------------------\n"); - fprintf(stream, - "VIN\n"); - fprintf(stream, + fprintf(stream, + "VIN\n"); + fprintf(stream, " I ptef0 pfet1 pfet2 pfet3 pfet4 pfet5 pfet6 pfet7\n" - "-----------------------------------------------------\n"); + "-----------------------------------------------------\n"); - for (i = 63 ; i >= 0; i--) { + for (i = 63 ; i >= 0; i--) { vdsvin_entry.value = revle64(lpsa->vdsvin[i].value); fprintf(stream, "%2u " "%-5u %-5u %-5u %-5u %-5u %-5u %-5u %-5u\n", i, - (uint8_t)vdsvin_entry.fields.pfet0, - (uint8_t)vdsvin_entry.fields.pfet1, - (uint8_t)vdsvin_entry.fields.pfet2, - (uint8_t)vdsvin_entry.fields.pfet3, - (uint8_t)vdsvin_entry.fields.pfet4, - (uint8_t)vdsvin_entry.fields.pfet5, - (uint8_t)vdsvin_entry.fields.pfet6, - (uint8_t)vdsvin_entry.fields.pfet7); - } - - fprintf(stream, - "-----------------------------------------------------\n\n"); -} + (uint8_t)vdsvin_entry.fields.pfet0, + (uint8_t)vdsvin_entry.fields.pfet1, + (uint8_t)vdsvin_entry.fields.pfet2, + (uint8_t)vdsvin_entry.fields.pfet3, + (uint8_t)vdsvin_entry.fields.pfet4, + (uint8_t)vdsvin_entry.fields.pfet5, + (uint8_t)vdsvin_entry.fields.pfet6, + (uint8_t)vdsvin_entry.fields.pfet7); + } + + fprintf(stream, + "-----------------------------------------------------\n\n"); +} /// Print CPM Pstate Range structure on a given stream /// @@ -532,26 +625,26 @@ void cpmrange_print(FILE* stream, CpmPstateModeRanges* cpmrange) { int i; - - fprintf(stream, - "---------------------------------------------------------------------------------------------------------\n"); + + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\n"); fprintf(stream, "CPM Pstate Range @ %p\n", cpmrange); - fprintf(stream, - "---------------------------------------------------------------------------------------------------------\n"); + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\n"); - fprintf(stream, "Valid Number of CPM Pstate Ranges : %u\n", + fprintf(stream, "Valid Number of CPM Pstate Ranges : %u\n", cpmrange->validRanges); - - for (i = 0; i < 8; i++) { - fprintf(stream, " CPM Range %d Pstate : %d\n", + + for (i = 0; i < 8; i++) { + fprintf(stream, " CPM Range %d Pstate : %d\n", i, cpmrange->inflectionPoint[i]); } - - fprintf(stream, " CPM Pmax : %d\n", - cpmrange->pMax); - - fprintf(stream, - "---------------------------------------------------------------------------------------------------------\n"); + + fprintf(stream, " CPM Pmax : %d\n", + cpmrange->pMax); + + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\n"); } /// Print a Resonant Clocking Setup structure on a given stream @@ -563,26 +656,242 @@ cpmrange_print(FILE* stream, CpmPstateModeRanges* cpmrange) void resclk_print(FILE* stream, ResonantClockingSetup* resclk) { - fprintf(stream, - "---------------------------------------------------------------------------------------------------------\n"); + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\n"); fprintf(stream, "Resonant Clocking Setup @ %p\n", resclk); - fprintf(stream, - "---------------------------------------------------------------------------------------------------------\n"); + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\n"); - fprintf(stream, "Full Clock Sector Buffer Pstate : %d\n", + fprintf(stream, " Full Clock Sector Buffer Pstate : %2d\n", resclk->full_csb_ps); - fprintf(stream, "Low Frequency Resonant Lower Pstate : %d\n", + fprintf(stream, " Low Frequency Resonant Lower Pstate : %2d\n", resclk->res_low_lower_ps); - fprintf(stream, "Low Frequency Resonant Upper Pstate : %d\n", + fprintf(stream, " Low Frequency Resonant Upper Pstate : %2d\n", resclk->res_low_upper_ps); - fprintf(stream, "High Frequency Resonant Lower Pstate : %d\n", + fprintf(stream, " High Frequency Resonant Lower Pstate : %2d\n", resclk->res_high_lower_ps); - fprintf(stream, "High Frequency Resonant Upper Pstate : %d\n", + fprintf(stream, " High Frequency Resonant Upper Pstate : %2d\n", resclk->res_high_upper_ps); + + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\n"); +} + +/// Print an IDDQ structure on a given stream +/// +/// \param stream The output stream +/// +/// \param iddq The IddqTable to print + +void +iddq_print(FILE* stream, IddqTable* iddq) +{ + uint32_t i, j; + const uint8_t vdd_measurement_order[LRP_IDDQ_RECORDS] = CORE_IDDQ_MEASUREMENTS_ORDER; + const char *core_measurement_str[LRP_IDDQ_RECORDS] = CORE_IDDQ_MEASUREMENT_VOLTAGES; + const uint8_t vcs_measurement_order[LRP_IDDQ_RECORDS] = CORE_IDDQ_MEASUREMENTS_ORDER; + const char *chip_measurement_str[CRP_IDDQ_RECORDS] = CHIP_IDDQ_MEASUREMENT_VOLTAGES; + const uint8_t vio_measurement_order[CRP_IDDQ_RECORDS] = CHIP_IDDQ_MEASUREMENTS_ORDER; + + + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\n"); + fprintf(stream, "IDDQ Table (version %d) @ %p\n", iddq->iddq_version, iddq); + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\n"); + + + for (i = 0; i < CORE_IDDQ_MEASUREMENTS; i++) { + for (j = 0; j < CORE_IDDQ_MEASUREMENTS; j++) { + if (vdd_measurement_order[j] == i) + fprintf(stream, " Core VDD IDDQ @ %sV Raw : 0x%04X, %6d mA; Temperature Corrected: 0x%04X, %6d mA\n", + core_measurement_str[j], + iddq->iddq_vdd[vdd_measurement_order[j]].fields.iddq_raw_value, + iddq->iddq_vdd[vdd_measurement_order[j]].fields.iddq_raw_value*10, + iddq->iddq_vdd[vdd_measurement_order[j]].fields.iddq_corrected_value, + iddq->iddq_vdd[vdd_measurement_order[j]].fields.iddq_corrected_value*10); + } + } + + for (i = 0; i < CORE_IDDQ_MEASUREMENTS; i++) { + for (j = 0; j < CORE_IDDQ_MEASUREMENTS; j++) { + if (vcs_measurement_order[j] == i) + fprintf(stream, " Core VCS IDDQ @ %sV Raw : 0x%04X, %6d mA; Temperature Corrected: 0x%04X, %6d mA\n", + core_measurement_str[j], + iddq->iddq_vcs[vcs_measurement_order[j]].fields.iddq_raw_value, + iddq->iddq_vcs[vcs_measurement_order[j]].fields.iddq_raw_value*10, + iddq->iddq_vcs[vcs_measurement_order[j]].fields.iddq_corrected_value, + iddq->iddq_vcs[vcs_measurement_order[j]].fields.iddq_corrected_value*10); + } + } + + for (i = 0; i < CHIP_IDDQ_MEASUREMENTS; i++) { + for (j = 0; j < CHIP_IDDQ_MEASUREMENTS; j++) { + if (vio_measurement_order[j] == i) + fprintf(stream, " Chip VIO IDDQ @ %sV Raw : 0x%04X, %6d mA; Temperature Corrected: 0x%04X, %6d mA\n", + chip_measurement_str[j], + iddq->iddq_vio[vio_measurement_order[j]].fields.iddq_raw_value, + iddq->iddq_vio[vio_measurement_order[j]].fields.iddq_raw_value*10, + iddq->iddq_vio[vio_measurement_order[j]].fields.iddq_corrected_value, + iddq->iddq_vio[vio_measurement_order[j]].fields.iddq_corrected_value*10); + } + } + + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\n"); +} + +// ENUM defining the printable rails +enum vidmod_rails +{ + VDD, + VCS +}; + +/// Print the VID Modification structure on a given stream +/// +/// \param stream The output stream +/// \param wof The WOF Element structure to print +/// \param rail The rail to put out +void +vidmod_print(FILE* stream, WOFElements* wof, vidmod_rails rail) +{ + char line_str[256]; + char entry_str[128]; - fprintf(stream, - "---------------------------------------------------------------------------------------------------------\n"); -} + uint8_t evid; + char evid_str[FORMAT_10UV_STRLEN]; + + strcpy(entry_str, ""); + strcpy(line_str, " Active Cores->"); + for (int j=0; j < wof->ut_vid_mod.ut_max_cores; ++j) + { + sprintf(entry_str, " %2d ", j+1); + strcat(line_str, entry_str); + } + fprintf(stream, "%s\n", line_str); + + strcpy(entry_str, ""); + strcpy(line_str, " Index Pstate "); + for (int j=0; j < wof->ut_vid_mod.ut_max_cores; ++j) + { + if (rail == VDD) + sprintf(entry_str, " evid_vdd(V) "); + else + sprintf(entry_str, " evid_vcs(V) "); + strcat(line_str, entry_str); + } + fprintf(stream, "%s\n", line_str); + + for (int i = wof->ut_vid_mod.ut_segment_pstates; i >= 0; --i) + { + + sprintf(line_str, " %2d %+4d ", + i, + -wof->ut_vid_mod.ut_segment_pstates+i); + + for (int j=0; j < wof->ut_vid_mod.ut_max_cores; ++j) + { + if (rail == VDD) + evid = wof->ut_vid_mod.ut_segment_vdd_vid[i][j]; + else + evid = wof->ut_vid_mod.ut_segment_vcs_vid[i][j]; + + sprintf_vrm11(evid_str, evid); + strcpy(entry_str, ""); + sprintf(entry_str, "0x%02x %s ", + evid, evid_str); + strcat(line_str, entry_str); + + } + fprintf(stream, "%s\n", line_str); + } + return; +} + +/// Print the WOF Element structure on a given stream +/// +/// \param stream The output stream +/// +/// \param wof The WOF Element structure to print + +void +wof_print(FILE* stream, WOFElements* wof) +{ + const char *vpd_point_str[VPD_PV_POINTS] = VPD_PV_ORDER_STR; + + char vpd_vdd_str[FORMAT_10UV_STRLEN]; + char vpd_vcs_str[FORMAT_10UV_STRLEN]; + char vpd_idd_str[FORMAT_IMA_STRLEN]; + char vpd_ics_str[FORMAT_IMA_STRLEN]; + + uint32_t vdd, vcs, idd, ics; + + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\n"); + fprintf(stream, "Workload Optimized Frequency (WOF) elements @ %p\n", wof); + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\n"); + + fprintf(stream, "WOF Enabled\t: %d\n", wof->wof_enabled); + + if (!wof->wof_enabled) + { + fprintf(stream, " >>>> With WOF Disabled, relevant content in the Pstate SuperStructure is not populated <<<<\n"); + } + + fprintf(stream, "VPD Points (biased without System Distribution Elements)\n"); + for (int i=0; i < VPD_PV_POINTS; ++i) + { + + vdd = wof->operating_points[i].vdd_5mv * 5 * 1000; + sprintf_10uv(vpd_vdd_str, vdd); + + vcs = wof->operating_points[i].vcs_5mv * 5 * 1000; + sprintf_10uv(vpd_vcs_str, vcs); + + idd = wof->operating_points[i].idd_500ma; + sprintf_vpd_current(vpd_idd_str, idd); + + ics = wof->operating_points[i].ics_500ma; + sprintf_vpd_current(vpd_ics_str, ics); + + fprintf(stream, " %s \t: %4d MHz VDD: %s V %s A VCS: %s V %s A\n", + vpd_point_str[i], + wof->operating_points[i].frequency_mhz, + vpd_vdd_str, + vpd_idd_str, + vpd_vcs_str, + vpd_ics_str + ); + } + + fprintf(stream, "System Distribution Elements\n"); + fprintf(stream, " VDD loadline : %d uOhm\n", wof->vdd_sysparm.loadline_uohm); + fprintf(stream, " VCS loadline : %d uOhm\n", wof->vcs_sysparm.loadline_uohm); + fprintf(stream, " VDD distribution loss : %d uOhm\n", wof->vdd_sysparm.distloss_uohm); + fprintf(stream, " VCS distribution loss : %d uOhm\n", wof->vcs_sysparm.distloss_uohm); + fprintf(stream, " VDD distribution offset : %d uV\n", wof->vdd_sysparm.distoffset_uv); + fprintf(stream, " VCS distribution offset : %d uV\n", wof->vcs_sysparm.distoffset_uv); + + fprintf(stream, "WOF Factors\n"); + fprintf(stream, " TDP to RDP factor 0x%X --> %0.2f%% \n", wof->tdp_rdp_factor, (double)wof->tdp_rdp_factor/100); + + fprintf(stream, "Pstates from Turbo to UltraTurbo (inclusive) : %d (from %-2d to %-2d)\n", + wof->ut_vid_mod.ut_segment_pstates+1, // +1 is for inclusivity + 0, + -(wof->ut_vid_mod.ut_segment_pstates)); + + + fprintf(stream, "Turbo<>UltraTurbo VID Modification - VDD\n"); + vidmod_print(stream, wof, VDD); + + fprintf(stream, "Turbo<>UltraTurbo VID Modification - VCS\n"); + vidmod_print(stream, wof, VCS); + + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\n"); +} /// Print a PstateSuperStructure on a given stream @@ -594,19 +903,26 @@ resclk_print(FILE* stream, ResonantClockingSetup* resclk) void pss_print(FILE* stream, PstateSuperStructure* pss) { - fprintf(stream, - "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); - fprintf(stream, "PstateSuperStructure @ %p\n", pss); - fprintf(stream, - "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); - + fprintf(stream, + "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); + fprintf(stream, "PstateSuperStructure @ %p; Size: %d bytes\n", pss, sizeof(PstateSuperStructure)); + fprintf(stream, + "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); + gpst_print(stream, &(pss->gpst)); lpsa_print(stream, &(pss->lpsa)); + cpmrange_print(stream, &(pss->cpmranges)); resclk_print(stream, &(pss->resclk)); - - fprintf(stream, - "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); + wof_print(stream, &(pss->wof)); + iddq_print(stream, &(pss->iddq)); + + fprintf(stream, + "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); } - -#endif // FAPIECMD + +#endif // FAPIECMD + +#ifdef __cplusplus +} // end extern C +#endif diff --git a/src/usr/hwpf/hwp/pstates/pstates/lab_pstates.h b/src/usr/hwpf/hwp/pstates/pstates/lab_pstates.h index c6da73d60..8d824011e 100755 --- a/src/usr/hwpf/hwp/pstates/pstates/lab_pstates.h +++ b/src/usr/hwpf/hwp/pstates/pstates/lab_pstates.h @@ -5,7 +5,9 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* COPYRIGHT International Business Machines Corp. 2013,2014 */ +/* Contributors Listed Below - COPYRIGHT 2013,2015 */ +/* [+] International Business Machines Corp. */ +/* */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ /* you may not use this file except in compliance with the License. */ @@ -23,7 +25,7 @@ #ifndef __LAB_PSTATES_H__ #define __LAB_PSTATES_H__ -// $Id: lab_pstates.h,v 1.5 2013/08/13 17:12:56 jimyac Exp $ +// $Id: lab_pstates.h,v 1.7 2015/06/01 19:02:17 stillgs Exp $ /// \file lab_pstates.h /// \brief Lab-only (as opposed to product-procedure) support for Pstates. @@ -43,6 +45,7 @@ /// /// \todo Replace with a typedef #define FORMAT_10UV_STRLEN 8 +#define FORMAT_IMA_STRLEN 8 #define FORMAT_10UV_ERROR "<Error>" @@ -51,6 +54,10 @@ #ifndef __ASSEMBLER__ +#ifdef __cplusplus +extern "C" { +#endif + int vuv2vrm11(uint32_t v_uv, int round, uint8_t *vrm11_vid); @@ -96,10 +103,20 @@ void resclk_print(FILE* stream, ResonantClockingSetup* resclk); void +iddq_print(FILE* stream, IddqTable* iddq); + +void +wof_print(FILE* stream, WOFElements* wof); + +void pss_print(FILE* stream, PstateSuperStructure* pss); #endif // FAPIECMD +#ifdef __cplusplus +} // end extern C +#endif + #endif // __ASSEMBLER__ #endif // __LAB_PSTATES_H__ diff --git a/src/usr/hwpf/hwp/pstates/pstates/p8_build_pstate_datablock.C b/src/usr/hwpf/hwp/pstates/pstates/p8_build_pstate_datablock.C index a9ec97d13..6def3a095 100755 --- a/src/usr/hwpf/hwp/pstates/pstates/p8_build_pstate_datablock.C +++ b/src/usr/hwpf/hwp/pstates/pstates/p8_build_pstate_datablock.C @@ -23,7 +23,7 @@ /* permissions and limitations under the License. */ /* */ /* IBM_PROLOG_END_TAG */ -// $Id: p8_build_pstate_datablock.C,v 1.44 2015/03/16 17:54:25 stillgs Exp $ +// $Id: p8_build_pstate_datablock.C,v 1.46 2015/06/01 18:50:36 stillgs Exp $ // $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/ipl/fapi/p8_build_pstate_datablock.C,v $ //------------------------------------------------------------------------------ // *! (C) Copyright International Business Machines Corp. 2012 @@ -64,20 +64,63 @@ extern "C" { -using namespace fapi; + using namespace fapi; // ---------------------------------------------------------------------- // Function prototypes // ---------------------------------------------------------------------- -ReturnCode proc_get_mvpd_data (const Target& i_target, uint32_t attr_mvpd_data[PV_D][PV_W], ivrm_mvpd_t *ivrm_mvpd, uint8_t *present_chiplets, uint8_t *functional_chiplets, uint8_t *poundm_valid, uint8_t *poundm_ver); -ReturnCode proc_get_attributes (const Target& i_target, AttributeList *attr_list); -ReturnCode proc_get_extint_bias (uint32_t attr_mvpd_data[PV_D][PV_W], const AttributeList *attr, double *volt_int_vdd_bias, double *volt_int_vcs_bias); -ReturnCode proc_boost_gpst (PstateSuperStructure *pss, uint32_t attr_boost_percent); -ReturnCode proc_upd_cpmrange (PstateSuperStructure *pss, const AttributeList *attr); -ReturnCode proc_upd_psafe_ps (PstateSuperStructure *pss, const AttributeList *attr); -ReturnCode proc_upd_floor_ps (PstateSuperStructure *pss, const AttributeList *attr); -ReturnCode proc_chk_valid_poundv (const Target& i_target, const uint32_t chiplet_mvpd_data[PV_D][PV_W], uint8_t chiplet_num, uint8_t bucket_id); -ReturnCode proc_res_clock (PstateSuperStructure *pss, AttributeList *attr_list); + ReturnCode proc_get_mvpd_data ( const Target& i_target, + AttributeList *attr, + uint32_t attr_mvpd_data[PV_D][PV_W], + uint32_t *valid_pdv_points, + ivrm_mvpd_t *ivrm_mvpd, + uint8_t *present_chiplets, + uint8_t *functional_chiplets, + uint8_t *poundm_valid, + uint8_t *poundm_ver); + + ReturnCode proc_get_mvpd_iddq ( const Target& i_target, + PstateSuperStructure *pss); + + ReturnCode proc_get_attributes ( const Target& i_target, + AttributeList *attr_list); + + ReturnCode proc_get_attributes ( const Target& i_target, + AttributeList *attr_list); + + ReturnCode proc_get_extint_bias ( uint32_t attr_mvpd_data[PV_D][PV_W], + const AttributeList *attr, + double *volt_int_vdd_bias, + double *volt_int_vcs_bias); + + ReturnCode proc_boost_gpst ( PstateSuperStructure *pss, + uint32_t attr_boost_percent); + + ReturnCode proc_upd_cpmrange ( PstateSuperStructure *pss, + const AttributeList *attr); + + ReturnCode proc_upd_psafe_ps ( PstateSuperStructure *pss, + const AttributeList *attr); + + ReturnCode proc_upd_floor_ps ( PstateSuperStructure *pss, + const AttributeList *attr); + + ReturnCode proc_chk_valid_poundv ( const Target& i_target, + AttributeList *attr, + const uint32_t chiplet_mvpd_data[PV_D][PV_W], + uint32_t *valid_pdv_points, + uint8_t chiplet_num, + uint8_t bucket_id); + + ReturnCode proc_res_clock ( PstateSuperStructure *pss, + AttributeList *attr_list); + + ReturnCode load_wof_attributes ( PstateSuperStructure *pss, + const AttributeList *attr); + + ReturnCode load_mvpd_operating_point (const uint32_t src[PV_D][PV_W], + VpdOperatingPoint *dest); + // ---------------------------------------------------------------------- // Function definitions // ---------------------------------------------------------------------- @@ -87,423 +130,561 @@ ReturnCode proc_res_clock (PstateSuperStructure *pss, AttributeList *attr /// \retval FAPI_RC_SUCCESS /// \retval ERROR defined in xml -ReturnCode -p8_build_pstate_datablock(const Target& i_target, - PstateSuperStructure *io_pss) -{ - fapi::ReturnCode l_rc; - int rc; - - AttributeList attr; - ChipCharacterization* characterization; - uint8_t i = 0; - uint8_t present_chiplets = 0; - uint8_t functional_chiplets = 0; - uint8_t poundm_ver = 0; - uint8_t poundm_valid = 1; // assume valid until code determines invalid - uint8_t lpst_valid = 1; // assume valid until code determines invalid - uint8_t attr_pm_ivrms_enabled_wr = 0; - uint8_t attr_pm_ivrms_enabled_rd = 0; - - const uint8_t pv_op_order[S132A_POINTS] = PV_OP_ORDER; - - double volt_int_vdd_bias = 1.0; - double volt_int_vcs_bias = 1.0; - - uint32_t frequency_step_khz = 0; - uint32_t attr_mvpd_voltage_control[PV_D][PV_W]; - - ivrm_mvpd_t ivrm_mvpd; - - FAPI_INF("Executing p8_build_pstate_datablock ...."); - - do - { - // ----------------------------------------------------------- - // Clear the PstateSuperStructure and install the magic number - // ----------------------------------------------------------- - memset(io_pss, 0, sizeof(*io_pss)); - (*io_pss).magic = revle64(PSTATE_SUPERSTRUCTURE_MAGIC); - - // ------------------------- - // get all attributes needed - // ------------------------- - FAPI_IMP("Getting Attributes to build Pstate Superstructure"); - - l_rc = proc_get_attributes(i_target , &attr ); - if (l_rc) break; - - // calculate pstate frequency step in Khz - frequency_step_khz = (attr.attr_freq_proc_refclock * 1000)/attr.attr_proc_dpll_divider; - - // -------------------------------- - // check chip ec feature attributes - // -------------------------------- - if (attr.attr_proc_ec_core_hang_pulse_bug) { - FAPI_INF("ATTR_PROC_EC_CORE_HANG_PULSE_BUG is set so disable iVRMs - setting PSTATE_NO_INSTALL_LPSA"); - (*io_pss).gpst.options.options = revle32(revle32((*io_pss).gpst.options.options) | - PSTATE_NO_INSTALL_LPSA); - poundm_valid = 0; - lpst_valid = 0; - } + ReturnCode + p8_build_pstate_datablock(const Target& i_target, + PstateSuperStructure *io_pss) + { + fapi::ReturnCode l_rc; + int rc; + + AttributeList attr; + ChipCharacterization* characterization; + uint8_t i = 0; + uint8_t present_chiplets = 0; + uint8_t functional_chiplets = 0; + uint8_t poundm_ver = 0; + uint8_t poundm_valid = + 1; // assume valid until code determines invalid + uint8_t lpst_valid = + 1; // assume valid until code determines invalid + + uint32_t valid_pdv_points = 0; + uint8_t attr_pm_ivrms_enabled_wr = 0; + uint8_t attr_pm_ivrms_enabled_rd = 0; - if (! attr.attr_chip_ec_feature_resonant_clk_valid) { - FAPI_INF("ATTR_CHIP_EC_FEATURE_RESONANT_CLK_VALID is not set so disable resonant clocking - setting PSTATE_NO_INSTALL_RESCLK"); - (*io_pss).gpst.options.options = revle32(revle32((*io_pss).gpst.options.options) | - PSTATE_NO_INSTALL_RESCLK ); - } + double volt_int_vdd_bias = 1.0; + double volt_int_vcs_bias = 1.0; - // ---------------- - // get #V & #M data - // ---------------- - FAPI_IMP("Getting #V & #M Data"); + uint32_t frequency_step_khz = 0; + uint32_t attr_mvpd_voltage_control[PV_D][PV_W]; - // clear array - memset(attr_mvpd_voltage_control, 0, sizeof(attr_mvpd_voltage_control)); - memset(&ivrm_mvpd, 0, sizeof(ivrm_mvpd)); + ivrm_mvpd_t ivrm_mvpd; - l_rc = proc_get_mvpd_data(i_target, attr_mvpd_voltage_control, &ivrm_mvpd, &present_chiplets, &functional_chiplets, £m_valid, £m_ver); - if (l_rc) { - break; - } - else if (!present_chiplets) { - FAPI_ERR("**** ERROR : There are no cores present"); - const uint8_t &PRESENT_CHIPLETS = present_chiplets; - const Target &CHIP_TARGET = i_target; - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_NO_CORES_PRESENT_ERROR); - break; - } + FAPI_INF("Executing p8_build_pstate_datablock ...."); - if (!functional_chiplets || !poundm_valid) { + do + { + // ----------------------------------------------------------- + // Clear the PstateSuperStructure and install the magic number + // ----------------------------------------------------------- + memset(io_pss, 0, sizeof(*io_pss)); + (*io_pss).magic = revle64(PSTATE_SUPERSTRUCTURE_MAGIC); - if (!functional_chiplets) - { - FAPI_IMP("No FUNCTIONAL chiplets found - set PSTATE_NO_INSTALL_LPSA"); - } - else - { - FAPI_IMP("Invalid #M found - set PSTATE_NO_INSTALL_LPSA"); - } + // ------------------------- + // get all attributes needed + // ------------------------- + FAPI_IMP("Getting Attributes to build Pstate Superstructure"); - // indicate no LPST installed in PSS - (*io_pss).gpst.options.options = revle32(revle32((*io_pss).gpst.options.options) | - PSTATE_NO_INSTALL_LPSA); - } + l_rc = proc_get_attributes(i_target , &attr ); - // --------------------------------------------- - // process external and internal bias attributes - // --------------------------------------------- - FAPI_IMP("Apply Biasing to #V"); - - l_rc = proc_get_extint_bias(attr_mvpd_voltage_control, &attr, &volt_int_vdd_bias, &volt_int_vcs_bias); - if (l_rc) break; - - // ----------------------------------------------- - // populate VpdOperatingPoint with MVPD attributes - // ----------------------------------------------- - // Assumes a constant 100mV dead zone - VpdOperatingPoint s132a_vpd[S132A_POINTS]; - - for (i = 0; i < S132A_POINTS; i++) { - s132a_vpd[i].frequency_mhz = attr_mvpd_voltage_control[pv_op_order[i]][0]; - s132a_vpd[i].vdd_5mv = attr_mvpd_voltage_control[pv_op_order[i]][1]; - s132a_vpd[i].idd_500ma = attr_mvpd_voltage_control[pv_op_order[i]][2]; - s132a_vpd[i].vdd_maxreg_5mv = attr_mvpd_voltage_control[pv_op_order[i]][1] - DEAD_ZONE_5MV; - s132a_vpd[i].vcs_5mv = attr_mvpd_voltage_control[pv_op_order[i]][3]; - s132a_vpd[i].ics_500ma = attr_mvpd_voltage_control[pv_op_order[i]][4]; - s132a_vpd[i].vcs_maxreg_5mv = attr_mvpd_voltage_control[pv_op_order[i]][3] - DEAD_ZONE_5MV; - } + if (l_rc) + { + break; + } - // ------------------------------------------------------------------- - // Create s132a_points and filled in by chip_characterization_create() - // ------------------------------------------------------------------- - OperatingPoint s132a_points[S132A_POINTS]; - - // ------------------------------------------------- - // populate OperatingPointParameters with attributes - // ------------------------------------------------- - // Parameters from a P7 system, consistent with s132a. We'll assume the - // package/header drop is 100uOhm for both Vdd and Vcs. - - OperatingPointParameters s132a_parms; - s132a_parms.pstate0_frequency_khz = ((s132a_vpd[S132A_POINTS-1].frequency_mhz * 1000) / frequency_step_khz) * frequency_step_khz; // pstate0 is turbo rounded down and forced to be a multiple of freq_step_khz - s132a_parms.frequency_step_khz = frequency_step_khz; // ATTR_REFCLK_FREQUENCY/ATTR_DPLL_DIVIDER - s132a_parms.vdd_load_line_uohm = attr.attr_proc_r_loadline_vdd; - s132a_parms.vcs_load_line_uohm = attr.attr_proc_r_loadline_vcs; - s132a_parms.vdd_distribution_uohm = attr.attr_proc_r_distloss_vdd; - s132a_parms.vcs_distribution_uohm = attr.attr_proc_r_distloss_vcs; - // SW267784 - s132a_parms.vdd_voffset_uv = attr.attr_proc_vrm_voffset_vdd; - s132a_parms.vcs_voffset_uv = attr.attr_proc_vrm_voffset_vcs; - - // -------------------------------------- - // Create Chip characterization structure - // -------------------------------------- - - ChipCharacterization s132a_characterization; - s132a_characterization.vpd = s132a_vpd; - s132a_characterization.ops = s132a_points; - s132a_characterization.parameters = &s132a_parms; - s132a_characterization.points = S132A_POINTS; - - // --------------------------- - // Finish the characterization - // --------------------------- - characterization = &s132a_characterization; - - rc = chip_characterization_create(characterization, - characterization->vpd, - characterization->ops, - characterization->parameters, - characterization->points); - - // check for error - int & CHAR_RETURN_CODE = rc; - if (rc == -GPST_INVALID_OBJECT) { - FAPI_ERR("**** ERROR : chip_characterization_create was passed null pointer to characterization or characterization->parameters"); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_CHARACTERIZATION_OBJECT_ERROR); - break; - } - else if (rc == -GPST_INVALID_ARGUMENT) { - int & POINTS = characterization->points; - FAPI_ERR("**** ERROR : chip_characterization_create was passed null pointer to characterization->vpd or no points"); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_CHARACTERIZATION_ARGUMENT_ERROR); - break; - } - else if (rc) { - FAPI_ERR("**** ERROR : chip_characterization_create returned error rc = %d", rc ); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_CHARACTERIZATION_ERROR); - break; - } + // calculate pstate frequency step in Khz + frequency_step_khz = (attr.attr_freq_proc_refclock * + 1000)/attr.attr_proc_dpll_divider; + + // -------------------------------- + // check chip ec feature attributes + // -------------------------------- + if (attr.attr_proc_ec_core_hang_pulse_bug) + { + FAPI_INF("ATTR_PROC_EC_CORE_HANG_PULSE_BUG is set so disable iVRMs - setting PSTATE_NO_INSTALL_LPSA"); + (*io_pss).gpst.options.options = revle32(revle32((*io_pss).gpst.options.options) + | + PSTATE_NO_INSTALL_LPSA); + poundm_valid = 0; + lpst_valid = 0; + } - // ------------------------------ - // Create the Global Pstate table - // ------------------------------ - FAPI_IMP("Creating Global Pstate Table"); - - rc = gpst_create(&((*io_pss).gpst), - characterization, - PSTATE_STEPSIZE, - EVRM_DELAY_NS); - - FAPI_INF("GPST vpd pmin = %d vpd pmax = %d vpd points = %d", s132a_characterization.ops[0].pstate, s132a_characterization.ops[s132a_characterization.points - 1].pstate, s132a_characterization.points); - FAPI_INF("GPST pmin = %d entries = %u", (*io_pss).gpst.pmin, (*io_pss).gpst.entries); - FAPI_INF("GPST refclock(Mhz) = %d pstate0_freq(Khz) = %d frequency_step(Khz) = %d", attr.attr_freq_proc_refclock, s132a_parms.pstate0_frequency_khz, s132a_parms.frequency_step_khz); - - // check for error - int & GPST_RETURN_CODE = rc; - if (rc == -GPST_INVALID_OBJECT) { - FAPI_ERR("**** ERROR : gpst_create was passed null pointer to gpst, characterization, or characterization->ops or characterization->points = 0"); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_GPST_CREATE_OBJECT_ERROR); - break; - } - else if (rc == -GPST_INVALID_ARGUMENT) { - int32_t & OPS_PMIN = s132a_characterization.ops[0].pstate; - int32_t & OPS_PMAX = s132a_characterization.ops[s132a_characterization.points - 1].pstate; - FAPI_ERR("**** ERROR : gpst_create was passed bad argument and resulted in PSTATE limits error or operating point ordering error"); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_GPST_CREATE_ARGUMENT_ERROR); - break; - } - else if (rc == -GPST_INVALID_ENTRY) { - FAPI_ERR("**** ERROR : gpst_entry_create was passed a voltage that was out of limits of vrm11 vid code or ivid vide code"); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_GPST_CREATE_ENTRY_ERROR); - break; - } - else if (rc) { - FAPI_ERR("**** ERROR : gpst_create returned error rc = %d", rc ); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_GPST_CREATE_ERROR); - break; - } + if (! attr.attr_chip_ec_feature_resonant_clk_valid) + { + FAPI_INF("ATTR_CHIP_EC_FEATURE_RESONANT_CLK_VALID is not set so disable resonant clocking - setting PSTATE_NO_INSTALL_RESCLK"); + (*io_pss).gpst.options.options = revle32(revle32((*io_pss).gpst.options.options) + | + PSTATE_NO_INSTALL_RESCLK ); + } - // ----------------------------- - // Boost the Global Pstate table - // ----------------------------- - FAPI_IMP("Boost Global Pstate Table per CPM Boost Attribute"); - - l_rc = proc_boost_gpst (io_pss, attr.attr_cpm_turbo_boost_percent); - if (l_rc) break; - - // -------------------------------------------------------------------- - // Setup psafe_pstate via attr_pm_safe_frequency (added per SW260812) - // -------------------------------------------------------------------- - FAPI_INF("Setup psafe_pstate via attr_pm_safe_frequency"); - - l_rc = proc_upd_psafe_ps (io_pss, &attr); - if (l_rc) break; - - // -------------------------------------------------------------------- - // Setup pmin_clip via attr_freq_core_floor (added per SW260911) - // -------------------------------------------------------------------- - FAPI_INF("Setup pmin_clip via attr_freq_core_floor"); - - l_rc = proc_upd_floor_ps (io_pss, &attr); - if (l_rc) break; - - // ----------------------------- - // Create the Local Pstate table - // ----------------------------- - uint8_t vid_incr_gt7_nonreg = 0; - - if (! attr.attr_proc_ec_core_hang_pulse_bug) { - FAPI_IMP("Creating Local Pstate Table"); - - rc = lpst_create( &((*io_pss).gpst), &((*io_pss).lpsa), DEAD_ZONE_5MV, volt_int_vdd_bias, volt_int_vcs_bias, &vid_incr_gt7_nonreg); - - int & LPST_RETURN_CODE = rc; - if (rc == -LPST_INVALID_OBJECT) { - FAPI_ERR("**** ERROR : lpst_create was passed null pointer to gpst or lpsa"); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_LPST_CREATE_OBJECT_ERROR); - break; - } - else if (rc == -IVID_INVALID_VOLTAGE) { - FAPI_ERR("**** ERROR : lpst_create attempted to convert an invalid voltage value to ivid format (GT 1.39375V or LT 0.6V"); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_LPST_CREATE_IVID_ERROR); - break; - } - else if (rc == -LPST_INCR_CLIP_ERROR) { - FAPI_ERR("**** ERROR : lpst_create encountered a vid increment > 7 in regulation"); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_LPST_CREATE_VID_INCR_CLIP_INREG_ERROR); - break; - } - else if (rc == -LPST_GPST_WARNING) { - FAPI_IMP("No Local Pstate Generated - Global Pstate Table is completely within Deadzone - set PSTATE_NO_INSTALL_LPSA" ); - - // indicate no LPST installed in PSS - (*io_pss).gpst.options.options = revle32(revle32((*io_pss).gpst.options.options) | - PSTATE_NO_INSTALL_LPSA); - lpst_valid = 0; - } - else if (rc) { - FAPI_ERR("**** ERROR : lpst_create returned error rc = %d", rc ); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_LPST_CREATE_ERROR); - break; - } - - // display warning message if this condition occurs - if (vid_incr_gt7_nonreg) { - FAPI_IMP("Warning : vid increment field was > 7 in non-regulation - clipped to 7 in lpst"); - } + // ---------------- + // get #V & #M data + // ---------------- + FAPI_IMP("Getting #V & #M Data"); + + // clear array + memset(attr_mvpd_voltage_control, 0, sizeof(attr_mvpd_voltage_control)); + memset(&ivrm_mvpd, 0, sizeof(ivrm_mvpd)); + + l_rc = proc_get_mvpd_data( i_target, + &attr, + attr_mvpd_voltage_control, + &valid_pdv_points, + &ivrm_mvpd, + &present_chiplets, + &functional_chiplets, + £m_valid, + £m_ver); + if (l_rc) + { + break; + } + else if (!present_chiplets) + { + FAPI_ERR("**** ERROR : There are no cores present"); + const uint8_t &PRESENT_CHIPLETS = present_chiplets; + const Target &CHIP_TARGET = i_target; + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_NO_CORES_PRESENT_ERROR); + break; + } - } + if (!functional_chiplets || !poundm_valid) + { + + if (!functional_chiplets) + { + FAPI_IMP("No FUNCTIONAL chiplets found - set PSTATE_NO_INSTALL_LPSA"); + } + else + { + FAPI_IMP("Invalid #M found - set PSTATE_NO_INSTALL_LPSA"); + } + + // indicate no LPST installed in PSS + (*io_pss).gpst.options.options = revle32(revle32((*io_pss).gpst.options.options) + | + PSTATE_NO_INSTALL_LPSA); + } - // ----------------------- - // Create VDS & VIN tables - // ----------------------- - FAPI_IMP("Create VDS & VIN Tables"); - - ivrm_parm_data_t ivrm_parms; - - // Set defaults - ivrm_parms.vin_min = 600; // Minimum input voltage - ivrm_parms.vin_max = 1375; // Maximum input voltage - ivrm_parms.vin_table_step_size = 25; // Granularity of Vin table entries - ivrm_parms.vin_table_setsperrow = 4; // Vin sets per Vds row - ivrm_parms.vin_table_pfetstrperset = 8; // PFET Strength values per Vin set - ivrm_parms.vout_min = 600; // Minimum regulated output voltage - ivrm_parms.vout_max = 1200; // Maximum regulated output voltage - ivrm_parms.vin_entries_per_vds = 32; // Vin array entries per vds region - ivrm_parms.vds_min_range_upper_bound = 100; // Starting point for vds regions - ivrm_parms.vds_step_percent = 25; // vds region step muliplier - ivrm_parms.vds_region_entries = 16; // vds region array entries (in hardware) - ivrm_parms.pfetstr_default = 0x11; // Default PFET Strength with no calibration - ivrm_parms.positive_guardband = 11; // Plus side guardband (%) - ivrm_parms.negative_guardband = 6; // Negative side guardband (%) - ivrm_parms.number_of_coefficients = 4; // Number of coefficents in cal data - ivrm_parms.force_pfetstr_values = 1; // 0 - calculated; 1 = forced - ivrm_parms.forced_pfetstr_value = 0x03; - - // create vds - build_vds_region_table(&ivrm_parms, io_pss); - - // loop over chiplets and find ones with valid data - // break after first valid chiplet since superstructure does not handle separate vin table for each chiplet - for (i = 0; i < CHIPLETS; i++) { - - if (ivrm_mvpd.data.ex[i].point_valid > 0) { - - // perform least squares fit to get coefficients & then fill in VIN table - fit_file(ivrm_parms.number_of_coefficients, - ivrm_mvpd.header.version, - ivrm_mvpd.data.ex[i].Coef, - &(ivrm_mvpd.data.ex[i]) ); - - write_HWtab_bin(&ivrm_parms, - ivrm_mvpd.data.ex[i].Coef, - io_pss); - break; - } - } + // --------------------------------------------- + // process external and internal bias attributes + // --------------------------------------------- + FAPI_IMP("Apply Biasing to #V"); - // --------------------------------------- - // Update CPM Range info in Superstructure - // --------------------------------------- - FAPI_IMP("Creating CPM Range Table"); + l_rc = proc_get_extint_bias(attr_mvpd_voltage_control, + &attr, + &volt_int_vdd_bias, + &volt_int_vcs_bias); - l_rc = proc_upd_cpmrange (io_pss, &attr); - if (l_rc) break; + if (l_rc) + { + break; + } - // ----------------------------------------------- - // Update Resonant Clocking info in Superstructure - // ----------------------------------------------- - if (attr.attr_chip_ec_feature_resonant_clk_valid) { - FAPI_IMP("Creating Resonant Clocking Band Table"); - l_rc = proc_res_clock (io_pss, &attr); - if (l_rc) break; - } + // ----------------------------------------------- + // populate VpdOperatingPoint with biased MVPD attributes + // ----------------------------------------------- + VpdOperatingPoint s132a_vpd[S132A_POINTS]; + + rc = load_mvpd_operating_point (attr_mvpd_voltage_control, + s132a_vpd); + + // ------------------------------------------------------------------- + // Create s132a_points and filled in by chip_characterization_create() + // ------------------------------------------------------------------- + OperatingPoint s132a_points[S132A_POINTS]; + + // ------------------------------------------------- + // populate OperatingPointParameters with attributes + // ------------------------------------------------- + + OperatingPointParameters s132a_parms; + s132a_parms.pstate0_frequency_khz = ((s132a_vpd[valid_pdv_points-1].frequency_mhz * + 1000) / frequency_step_khz) * + frequency_step_khz; + // pstate0 is turbo rounded down and forced to be a multiple of freq_step_khz + s132a_parms.frequency_step_khz = + frequency_step_khz; // ATTR_REFCLK_FREQUENCY/ATTR_DPLL_DIVIDER + s132a_parms.vdd_load_line_uohm = attr.attr_proc_r_loadline_vdd; + s132a_parms.vcs_load_line_uohm = attr.attr_proc_r_loadline_vcs; + s132a_parms.vdd_distribution_uohm = attr.attr_proc_r_distloss_vdd; + s132a_parms.vcs_distribution_uohm = attr.attr_proc_r_distloss_vcs; + // SW267784 + s132a_parms.vdd_voffset_uv = attr.attr_proc_vrm_voffset_vdd; + s132a_parms.vcs_voffset_uv = attr.attr_proc_vrm_voffset_vcs; + + + // -------------------------------------- + // Create Chip characterization structure + // -------------------------------------- + + ChipCharacterization s132a_characterization; + s132a_characterization.vpd = s132a_vpd; + s132a_characterization.ops = s132a_points; + s132a_characterization.parameters = &s132a_parms; + s132a_characterization.points = valid_pdv_points; + s132a_characterization.max_cores = present_chiplets; + + // --------------------------- + // Finish the characterization + // --------------------------- + characterization = &s132a_characterization; + + rc = chip_characterization_create(characterization, + characterization->vpd, + characterization->ops, + characterization->parameters, + characterization->points); + + // check for error + int & CHAR_RETURN_CODE = rc; + + if (rc == -GPST_INVALID_OBJECT) + { + FAPI_ERR("**** ERROR : chip_characterization_create was passed null pointer to characterization or characterization->parameters"); + FAPI_SET_HWP_ERROR(l_rc, + RC_PROCPM_PSTATE_DATABLOCK_CHARACTERIZATION_OBJECT_ERROR); + break; + } + else if (rc == -GPST_INVALID_ARGUMENT) + { + uint32_t & POINTS = characterization->points; + FAPI_ERR("**** ERROR : chip_characterization_create was passed null pointer to characterization->vpd or no points"); + FAPI_SET_HWP_ERROR(l_rc, + RC_PROCPM_PSTATE_DATABLOCK_CHARACTERIZATION_ARGUMENT_ERROR); + break; + } + else if (rc) + { + FAPI_ERR("**** ERROR : chip_characterization_create returned error rc = %d", + rc ); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_CHARACTERIZATION_ERROR); + break; + } - // ------------------------ - // Force optional overrides - // ------------------------ - FAPI_INF(" Set PSTATE_FORCE_INITIAL_PMIN in GPST control options"); - (*io_pss).gpst.options.options = revle32(revle32((*io_pss).gpst.options.options) | PSTATE_FORCE_INITIAL_PMIN); - FAPI_INF(" GPST control options mask is now: [%x].", (*io_pss).gpst.options.options); - - // ------------------- - // Attributes to write - // ------------------- - // uint32_t ATTR_PM_PSTATE0_FREQUENCY // Binary in Khz - FAPI_IMP("Writing Attribute Values"); - - // check if IVRMs should be enabled - if (poundm_valid && lpst_valid && // IVRMs should be enabled based on VPD findings - attr.attr_pm_system_ivrms_enabled && // Allowed by system - (attr.attr_pm_system_ivrm_vpd_min_level != 0) && // Attribute has a valid value - (attr.attr_pm_system_ivrm_vpd_min_level >= poundm_ver) && // Hardware characterized - attr.attr_chip_ec_feature_ivrm_winkle_bug) // Hardware has logic fixes - { - attr_pm_ivrms_enabled_wr = 1; - } - else - { - attr_pm_ivrms_enabled_wr = 0; - FAPI_INF(" ATTR_PM_IVRMS_ENABLED will be set to 0 - set PSTATE_NO_INSTALL_LPSA"); - // indicate no LPST installed in PSS - (*io_pss).gpst.options.options = revle32(revle32((*io_pss).gpst.options.options) | - PSTATE_NO_INSTALL_LPSA); - } + // Load the WOF information as this influences the generation + // of the Pstate tables + if (attr.attr_wof_enabled) + { + // ----------------------------------------------- + // populate WOF structure with the biased VPD information + // ----------------------------------------------- + l_rc = load_mvpd_operating_point (attr_mvpd_voltage_control, + io_pss->wof.operating_points); + if (l_rc) + { + // No errors to handle at this time + } + + // ---------------- + // get IQ (IDDQ) data and place into the Pstate SuperStructure + // ---------------- + FAPI_IMP("Getting IQ (IDDQ) Data"); + + l_rc = proc_get_mvpd_iddq(i_target, io_pss); + if (l_rc) + { + // @todo add FFDC + + // Disable WOF and keep going + FAPI_INF("**** WARNING: While WOF was enabled via attributes, IDDQ information " + "for the present part could not be obtained (either due to access error " + "or is not present in the VPD. WOF is being DISABLED but Pstate table " + "generation is continuing"); + attr.attr_wof_enabled = 0; + + } + else + { + // ----------------------------------------------- + // populate WOF structure with the biased VPD information + // ----------------------------------------------- + rc = load_wof_attributes (io_pss, &attr); + if (l_rc) + { + // No errors to handle at this time + } + } + } - // write ATTR_PM_IVRMS_ENABLED - SETATTR(l_rc, ATTR_PM_IVRMS_ENABLED, "ATTR_PM_IVRMS_ENABLED", &i_target, attr_pm_ivrms_enabled_wr); - // Read back attribute to see if overridden - GETATTR (l_rc, ATTR_PM_IVRMS_ENABLED, "ATTR_PM_IVRMS_ENABLED", &i_target, attr_pm_ivrms_enabled_rd); + // ------------------------------ + // Create the Global Pstate table + // ------------------------------ + FAPI_IMP("Creating Global Pstate Table"); + + rc = gpst_create(&((*io_pss).gpst), + characterization, + &((*io_pss).wof), + PSTATE_STEPSIZE, + EVRM_DELAY_NS); + + FAPI_INF("GPST vpd pmin = %d vpd pmax = %d vpd points = %d", + s132a_characterization.ops[0].pstate, + s132a_characterization.ops[s132a_characterization.points - 1].pstate, + s132a_characterization.points); + FAPI_INF("GPST pmin = %d entries = %u", (*io_pss).gpst.pmin, + (*io_pss).gpst.entries); + FAPI_INF("GPST refclock(Mhz) = %d pstate0_freq(Khz) = %d frequency_step(Khz) = %d", + attr.attr_freq_proc_refclock, s132a_parms.pstate0_frequency_khz, + s132a_parms.frequency_step_khz); + + // check for error + int & GPST_RETURN_CODE = rc; + + if (rc == -GPST_INVALID_OBJECT) + { + FAPI_ERR("**** ERROR : gpst_create was passed null pointer to gpst, characterization, or characterization->ops or characterization->points = 0"); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_GPST_CREATE_OBJECT_ERROR); + break; + } + else if (rc == -GPST_INVALID_ARGUMENT) + { + int32_t & OPS_PMIN = s132a_characterization.ops[0].pstate; + int32_t & OPS_PMAX = + s132a_characterization.ops[s132a_characterization.points - 1].pstate; + FAPI_ERR("**** ERROR : gpst_create was passed bad argument and resulted in PSTATE limits error or operating point ordering error"); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_GPST_CREATE_ARGUMENT_ERROR); + break; + } + else if (rc == -GPST_INVALID_ENTRY) + { + FAPI_ERR("**** ERROR : gpst_entry_create was passed a voltage that was out of limits of vrm11 vid code or ivid vide code"); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_GPST_CREATE_ENTRY_ERROR); + break; + } + else if (rc) + { + FAPI_ERR("**** ERROR : gpst_create returned error rc = %d", rc ); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_GPST_CREATE_ERROR); + break; + } - if (attr_pm_ivrms_enabled_rd && !attr_pm_ivrms_enabled_wr) { - FAPI_INF("WARNING : Attribute ATTR_PM_IVRMS_ENABLED was overridden to 1, but #V or #M data is not valid for IVRMs"); - } - else if (!attr_pm_ivrms_enabled_rd && attr_pm_ivrms_enabled_wr) { - FAPI_INF("WARNING : ATTR_PM_IVRMS_ENABLED was overriden to 0, but #V or #M data are valid - set PSTATE_NO_INSTALL_LPSA"); - // indicate no LPST installed in PSS - (*io_pss).gpst.options.options = revle32(revle32((*io_pss).gpst.options.options) | - PSTATE_NO_INSTALL_LPSA); - } + // ----------------------------- + // Boost the Global Pstate table + // ----------------------------- + FAPI_IMP("Boost Global Pstate Table per CPM Boost Attribute"); - } while(0); + l_rc = proc_boost_gpst (io_pss, attr.attr_cpm_turbo_boost_percent); + + if (l_rc) + { + break; + } + + // -------------------------------------------------------------------- + // Setup psafe_pstate via attr_pm_safe_frequency (added per SW260812) + // -------------------------------------------------------------------- + FAPI_INF("Setup psafe_pstate via attr_pm_safe_frequency"); + + l_rc = proc_upd_psafe_ps (io_pss, &attr); + + if (l_rc) + { + break; + } + + // -------------------------------------------------------------------- + // Setup pmin_clip via attr_freq_core_floor (added per SW260911) + // -------------------------------------------------------------------- + FAPI_INF("Setup pmin_clip via attr_freq_core_floor"); + + l_rc = proc_upd_floor_ps (io_pss, &attr); + + if (l_rc) + { + break; + } + + // ----------------------------- + // Create the Local Pstate table + // ----------------------------- + uint8_t vid_incr_gt7_nonreg = 0; + + if (! attr.attr_proc_ec_core_hang_pulse_bug) + { + FAPI_IMP("Creating Local Pstate Table"); + + rc = lpst_create( &((*io_pss).gpst), &((*io_pss).lpsa), DEAD_ZONE_5MV, + volt_int_vdd_bias, volt_int_vcs_bias, &vid_incr_gt7_nonreg); + + int & LPST_RETURN_CODE = rc; + + if (rc == -LPST_INVALID_OBJECT) + { + FAPI_ERR("**** ERROR : lpst_create was passed null pointer to gpst or lpsa"); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_LPST_CREATE_OBJECT_ERROR); + break; + } + else if (rc == -IVID_INVALID_VOLTAGE) + { + FAPI_ERR("**** ERROR : lpst_create attempted to convert an invalid voltage value to ivid format (GT 1.39375V or LT 0.6V"); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_LPST_CREATE_IVID_ERROR); + break; + } + else if (rc == -LPST_INCR_CLIP_ERROR) + { + FAPI_ERR("**** ERROR : lpst_create encountered a vid increment > 7 in regulation"); + FAPI_SET_HWP_ERROR(l_rc, + RC_PROCPM_PSTATE_DATABLOCK_LPST_CREATE_VID_INCR_CLIP_INREG_ERROR); + break; + } + else if (rc == -LPST_GPST_WARNING) + { + FAPI_IMP("No Local Pstate Generated - Global Pstate Table is completely within Deadzone - set PSTATE_NO_INSTALL_LPSA" ); + + // indicate no LPST installed in PSS + (*io_pss).gpst.options.options = revle32(revle32((*io_pss).gpst.options.options) + | + PSTATE_NO_INSTALL_LPSA); + lpst_valid = 0; + } + else if (rc) + { + FAPI_ERR("**** ERROR : lpst_create returned error rc = %d", rc ); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_LPST_CREATE_ERROR); + break; + } + + // display warning message if this condition occurs + if (vid_incr_gt7_nonreg) + { + FAPI_IMP("Warning : vid increment field was > 7 in non-regulation - clipped to 7 in lpst"); + } + + } + + // ----------------------- + // Create VDS & VIN tables + // ----------------------- + FAPI_IMP("Create VDS & VIN Tables"); + + ivrm_parm_data_t ivrm_parms; + + // Set defaults + ivrm_parms.vin_min = 600; // Minimum input voltage + ivrm_parms.vin_max = 1375; // Maximum input voltage + ivrm_parms.vin_table_step_size = 25; // Granularity of Vin table entries + ivrm_parms.vin_table_setsperrow = 4; // Vin sets per Vds row + ivrm_parms.vin_table_pfetstrperset = 8; // PFET Strength values per Vin set + ivrm_parms.vout_min = 600; // Minimum regulated output voltage + ivrm_parms.vout_max = 1200; // Maximum regulated output voltage + ivrm_parms.vin_entries_per_vds = 32; // Vin array entries per vds region + ivrm_parms.vds_min_range_upper_bound = 100; // Starting point for vds regions + ivrm_parms.vds_step_percent = 25; // vds region step muliplier + ivrm_parms.vds_region_entries = 16; // vds region array entries (in hardware) + ivrm_parms.pfetstr_default = 0x11; // Default PFET Strength with no calibration + ivrm_parms.positive_guardband = 11; // Plus side guardband (%) + ivrm_parms.negative_guardband = 6; // Negative side guardband (%) + ivrm_parms.number_of_coefficients = 4; // Number of coefficents in cal data + ivrm_parms.force_pfetstr_values = 1; // 0 - calculated; 1 = forced + ivrm_parms.forced_pfetstr_value = 0x03; + + // create vds + build_vds_region_table(&ivrm_parms, io_pss); + + // loop over chiplets and find ones with valid data + // break after first valid chiplet since superstructure does not handle separate vin table for each chiplet + for (i = 0; i < CHIPLETS; i++) + { + + if (ivrm_mvpd.data.ex[i].point_valid > 0) + { + + // perform least squares fit to get coefficients & then fill in VIN table + fit_file(ivrm_parms.number_of_coefficients, + ivrm_mvpd.header.version, + ivrm_mvpd.data.ex[i].Coef, + &(ivrm_mvpd.data.ex[i]) ); + + write_HWtab_bin(&ivrm_parms, + ivrm_mvpd.data.ex[i].Coef, + io_pss); + break; + } + } + + // --------------------------------------- + // Update CPM Range info in Superstructure + // --------------------------------------- + FAPI_IMP("Creating CPM Range Table"); + + l_rc = proc_upd_cpmrange (io_pss, &attr); + + if (l_rc) + { + break; + } - return l_rc; -} // end p8_build_pstate_datablock + // ----------------------------------------------- + // Update Resonant Clocking info in Superstructure + // ----------------------------------------------- + if (attr.attr_chip_ec_feature_resonant_clk_valid) + { + FAPI_IMP("Creating Resonant Clocking Band Table"); + l_rc = proc_res_clock (io_pss, &attr); + + if (l_rc) + { + break; + } + } + + // ------------------------ + // Force optional overrides + // ------------------------ + FAPI_INF(" Set PSTATE_FORCE_INITIAL_PMIN in GPST control options"); + (*io_pss).gpst.options.options = revle32(revle32((*io_pss).gpst.options.options) + | PSTATE_FORCE_INITIAL_PMIN); + FAPI_INF(" GPST control options mask is now: [%x].", + (*io_pss).gpst.options.options); + + // ------------------- + // Attributes to write + // ------------------- + // uint32_t ATTR_PM_PSTATE0_FREQUENCY // Binary in Khz + FAPI_IMP("Writing Attribute Values"); + + // check if IVRMs should be enabled + if (poundm_valid && lpst_valid + && // IVRMs should be enabled based on VPD findings + attr.attr_pm_system_ivrms_enabled && // Allowed by system + (attr.attr_pm_system_ivrm_vpd_min_level != 0) + && // Attribute has a valid value + (attr.attr_pm_system_ivrm_vpd_min_level >= poundm_ver) + && // Hardware characterized + attr.attr_chip_ec_feature_ivrm_winkle_bug) // Hardware has logic fixes + { + attr_pm_ivrms_enabled_wr = 1; + } + else + { + attr_pm_ivrms_enabled_wr = 0; + FAPI_INF(" ATTR_PM_IVRMS_ENABLED will be set to 0 - set PSTATE_NO_INSTALL_LPSA"); + // indicate no LPST installed in PSS + (*io_pss).gpst.options.options = revle32(revle32((*io_pss).gpst.options.options) + | + PSTATE_NO_INSTALL_LPSA); + } + + // write ATTR_PM_IVRMS_ENABLED + SETATTR(l_rc, ATTR_PM_IVRMS_ENABLED, "ATTR_PM_IVRMS_ENABLED", &i_target, + attr_pm_ivrms_enabled_wr); + + // Read back attribute to see if overridden + GETATTR (l_rc, ATTR_PM_IVRMS_ENABLED, "ATTR_PM_IVRMS_ENABLED", &i_target, + attr_pm_ivrms_enabled_rd); + + if (attr_pm_ivrms_enabled_rd && !attr_pm_ivrms_enabled_wr) + { + FAPI_INF("WARNING : Attribute ATTR_PM_IVRMS_ENABLED was overridden to 1, but #V or #M data is not valid for IVRMs"); + } + else if (!attr_pm_ivrms_enabled_rd && attr_pm_ivrms_enabled_wr) + { + FAPI_INF("WARNING : ATTR_PM_IVRMS_ENABLED was overriden to 0, but #V or #M data are valid - set PSTATE_NO_INSTALL_LPSA"); + // indicate no LPST installed in PSS + (*io_pss).gpst.options.options = revle32(revle32((*io_pss).gpst.options.options) + | + PSTATE_NO_INSTALL_LPSA); + } + + } + while(0); + + return l_rc; + } // end p8_build_pstate_datablock /// ----------------------------------------------------------------------- /// \brief Get needed attributes @@ -511,46 +692,49 @@ p8_build_pstate_datablock(const Target& i_target, /// \param[inout] attr => pointer to attribute list structure /// ----------------------------------------------------------------------- -ReturnCode proc_get_attributes(const Target& i_target, - AttributeList *attr) -{ - ReturnCode l_rc; - uint8_t i = 0; - - do - { - // -------------------------- - // attributes not yet defined - // -------------------------- - attr->attr_dpll_bias = 0; - attr->attr_undervolting = 0; - - // --------------------------------------------------------------- - // set ATTR_PROC_DPLL_DIVIDER - // --------------------------------------------------------------- - attr->attr_proc_dpll_divider = 4; - FAPI_INF("ATTR_PROC_DPLL_DIVIDER - set to %x", attr->attr_proc_dpll_divider); - - l_rc = FAPI_ATTR_SET(ATTR_PROC_DPLL_DIVIDER, &i_target, attr->attr_proc_dpll_divider ); - if (l_rc ) { - FAPI_ERR("fapiSetAttribute of ATTR_PROC_DPLL_DIVIDER failed"); - break; - } + ReturnCode proc_get_attributes(const Target& i_target, + AttributeList *attr) + { + ReturnCode l_rc; + uint8_t i = 0; + + do + { + // -------------------------- + // attributes not yet defined + // -------------------------- + attr->attr_dpll_bias = 0; + attr->attr_undervolting = 0; + + // --------------------------------------------------------------- + // set ATTR_PROC_DPLL_DIVIDER + // --------------------------------------------------------------- + attr->attr_proc_dpll_divider = 4; + FAPI_INF("ATTR_PROC_DPLL_DIVIDER - set to %x", attr->attr_proc_dpll_divider); + + l_rc = FAPI_ATTR_SET(ATTR_PROC_DPLL_DIVIDER, &i_target, + attr->attr_proc_dpll_divider ); + + if (l_rc ) + { + FAPI_ERR("fapiSetAttribute of ATTR_PROC_DPLL_DIVIDER failed"); + break; + } - // ---------------------------- - // attributes currently defined - // ---------------------------- - #define DATABLOCK_GET_ATTR(attr_name, target, attr_assign) \ + // ---------------------------- + // attributes currently defined + // ---------------------------- +#define DATABLOCK_GET_ATTR(attr_name, target, attr_assign) \ l_rc = FAPI_ATTR_GET(attr_name, target, attr->attr_assign); \ if (l_rc) break; \ FAPI_INF("%-60s = 0x%08x %u", #attr_name, attr->attr_assign, attr->attr_assign); - - // This macro is in place to to deal with the movement of attribute placement - // from SYSTEM to PROC_CHIP per SW298278 hhile allowing for this procedure - // to still operate in system that continue store attributes at the SYSTEM level. - // This is done by trying the passed target first; if it doesn't succeed, the - // SYSTEM level is attempted. Failure of both will cause a break. - #define DATABLOCK_GET_ATTR_CHECK_PROC(attr_name, target, attr_assign) \ + + // This macro is in place to to deal with the movement of attribute placement + // from SYSTEM to PROC_CHIP per SW298278 while allowing for this procedure + // to still operate in system that continue store attributes at the SYSTEM level. + // This is done by trying the passed target first; if it doesn't succeed, the + // SYSTEM level is attempted. Failure of both will cause a break. +#define DATABLOCK_GET_ATTR_CHECK_PROC(attr_name, target, attr_assign) \ l_rc = FAPI_ATTR_GET(attr_name, target, attr->attr_assign); \ if (!l_rc) { \ FAPI_INF("%-60s = 0x%08x %u from PROC_CHIP target", #attr_name, attr->attr_assign, attr->attr_assign); \ @@ -566,420 +750,859 @@ ReturnCode proc_get_attributes(const Target& i_target, break; \ } \ } + + DATABLOCK_GET_ATTR(ATTR_FREQ_EXT_BIAS_UP, + &i_target, attr_freq_ext_bias_up); + DATABLOCK_GET_ATTR(ATTR_FREQ_EXT_BIAS_DOWN, + &i_target, attr_freq_ext_bias_down); + DATABLOCK_GET_ATTR(ATTR_VOLTAGE_EXT_VDD_BIAS_UP, + &i_target, attr_voltage_ext_vdd_bias_up); + DATABLOCK_GET_ATTR(ATTR_VOLTAGE_EXT_VCS_BIAS_UP, + &i_target, attr_voltage_ext_vcs_bias_up); + DATABLOCK_GET_ATTR(ATTR_VOLTAGE_EXT_VDD_BIAS_DOWN, + &i_target, attr_voltage_ext_vdd_bias_down); + DATABLOCK_GET_ATTR(ATTR_VOLTAGE_EXT_VCS_BIAS_DOWN, + &i_target, attr_voltage_ext_vcs_bias_down); + DATABLOCK_GET_ATTR(ATTR_VOLTAGE_INT_VDD_BIAS_UP, + &i_target, attr_voltage_int_vdd_bias_up); + DATABLOCK_GET_ATTR(ATTR_VOLTAGE_INT_VCS_BIAS_UP, + &i_target, attr_voltage_int_vcs_bias_up); + DATABLOCK_GET_ATTR(ATTR_VOLTAGE_INT_VDD_BIAS_DOWN, + &i_target, attr_voltage_int_vdd_bias_down); + DATABLOCK_GET_ATTR(ATTR_VOLTAGE_INT_VCS_BIAS_DOWN, + &i_target, attr_voltage_int_vcs_bias_down); + DATABLOCK_GET_ATTR(ATTR_FREQ_PROC_REFCLOCK, + NULL, attr_freq_proc_refclock); + DATABLOCK_GET_ATTR(ATTR_FREQ_CORE_MAX, + NULL, attr_freq_core_max); + DATABLOCK_GET_ATTR(ATTR_PM_SAFE_FREQUENCY, + NULL, attr_pm_safe_frequency); + DATABLOCK_GET_ATTR(ATTR_FREQ_CORE_FLOOR, + NULL, attr_freq_core_floor); + DATABLOCK_GET_ATTR(ATTR_BOOT_FREQ_MHZ, + NULL, attr_boot_freq_mhz); + DATABLOCK_GET_ATTR(ATTR_CPM_TURBO_BOOST_PERCENT, + NULL, attr_cpm_turbo_boost_percent); + + DATABLOCK_GET_ATTR_CHECK_PROC(ATTR_PROC_R_LOADLINE_VDD, + &i_target, attr_proc_r_loadline_vdd); + DATABLOCK_GET_ATTR_CHECK_PROC(ATTR_PROC_R_LOADLINE_VCS, + &i_target, attr_proc_r_loadline_vcs); + DATABLOCK_GET_ATTR_CHECK_PROC(ATTR_PROC_R_DISTLOSS_VDD, + &i_target, attr_proc_r_distloss_vdd); + DATABLOCK_GET_ATTR_CHECK_PROC(ATTR_PROC_R_DISTLOSS_VCS, + &i_target, attr_proc_r_distloss_vcs); + DATABLOCK_GET_ATTR_CHECK_PROC(ATTR_PROC_VRM_VOFFSET_VDD, + &i_target, attr_proc_vrm_voffset_vdd); + DATABLOCK_GET_ATTR_CHECK_PROC(ATTR_PROC_VRM_VOFFSET_VCS, + &i_target, attr_proc_vrm_voffset_vcs); + + DATABLOCK_GET_ATTR(ATTR_PM_RESONANT_CLOCK_FULL_CLOCK_SECTOR_BUFFER_FREQUENCY, + NULL, attr_pm_resonant_clock_full_clock_sector_buffer_frequency); + DATABLOCK_GET_ATTR(ATTR_PM_RESONANT_CLOCK_LOW_BAND_LOWER_FREQUENCY, + NULL, attr_pm_resonant_clock_low_band_lower_frequency); + DATABLOCK_GET_ATTR(ATTR_PM_RESONANT_CLOCK_LOW_BAND_UPPER_FREQUENCY, + NULL, attr_pm_resonant_clock_low_band_upper_frequency); + DATABLOCK_GET_ATTR(ATTR_PM_RESONANT_CLOCK_HIGH_BAND_LOWER_FREQUENCY, + NULL, attr_pm_resonant_clock_high_band_lower_frequency); + DATABLOCK_GET_ATTR(ATTR_PM_RESONANT_CLOCK_HIGH_BAND_UPPER_FREQUENCY, + NULL, attr_pm_resonant_clock_high_band_upper_frequency); + + // Read array attribute + l_rc = FAPI_ATTR_GET(ATTR_CPM_INFLECTION_POINTS, &i_target, + attr->attr_cpm_inflection_points); + + if (l_rc) + { + break; + } - DATABLOCK_GET_ATTR(ATTR_FREQ_EXT_BIAS_UP, &i_target, attr_freq_ext_bias_up); - DATABLOCK_GET_ATTR(ATTR_FREQ_EXT_BIAS_DOWN, &i_target, attr_freq_ext_bias_down); - DATABLOCK_GET_ATTR(ATTR_VOLTAGE_EXT_VDD_BIAS_UP, &i_target, attr_voltage_ext_vdd_bias_up); - DATABLOCK_GET_ATTR(ATTR_VOLTAGE_EXT_VCS_BIAS_UP, &i_target, attr_voltage_ext_vcs_bias_up); - DATABLOCK_GET_ATTR(ATTR_VOLTAGE_EXT_VDD_BIAS_DOWN, &i_target, attr_voltage_ext_vdd_bias_down); - DATABLOCK_GET_ATTR(ATTR_VOLTAGE_EXT_VCS_BIAS_DOWN, &i_target, attr_voltage_ext_vcs_bias_down); - DATABLOCK_GET_ATTR(ATTR_VOLTAGE_INT_VDD_BIAS_UP, &i_target, attr_voltage_int_vdd_bias_up); - DATABLOCK_GET_ATTR(ATTR_VOLTAGE_INT_VCS_BIAS_UP, &i_target, attr_voltage_int_vcs_bias_up); - DATABLOCK_GET_ATTR(ATTR_VOLTAGE_INT_VDD_BIAS_DOWN, &i_target, attr_voltage_int_vdd_bias_down); - DATABLOCK_GET_ATTR(ATTR_VOLTAGE_INT_VCS_BIAS_DOWN, &i_target, attr_voltage_int_vcs_bias_down); - DATABLOCK_GET_ATTR(ATTR_FREQ_PROC_REFCLOCK, NULL, attr_freq_proc_refclock); - DATABLOCK_GET_ATTR(ATTR_FREQ_CORE_MAX, NULL, attr_freq_core_max); - DATABLOCK_GET_ATTR(ATTR_PM_SAFE_FREQUENCY, NULL, attr_pm_safe_frequency); - DATABLOCK_GET_ATTR(ATTR_FREQ_CORE_FLOOR, NULL, attr_freq_core_floor); - DATABLOCK_GET_ATTR(ATTR_BOOT_FREQ_MHZ, NULL, attr_boot_freq_mhz); - DATABLOCK_GET_ATTR(ATTR_CPM_TURBO_BOOST_PERCENT, NULL, attr_cpm_turbo_boost_percent); - - DATABLOCK_GET_ATTR_CHECK_PROC(ATTR_PROC_R_LOADLINE_VDD, &i_target, attr_proc_r_loadline_vdd); - DATABLOCK_GET_ATTR_CHECK_PROC(ATTR_PROC_R_LOADLINE_VCS, &i_target, attr_proc_r_loadline_vcs); - DATABLOCK_GET_ATTR_CHECK_PROC(ATTR_PROC_R_DISTLOSS_VDD, &i_target, attr_proc_r_distloss_vdd); - DATABLOCK_GET_ATTR_CHECK_PROC(ATTR_PROC_R_DISTLOSS_VCS, &i_target, attr_proc_r_distloss_vcs); - DATABLOCK_GET_ATTR_CHECK_PROC(ATTR_PROC_VRM_VOFFSET_VDD, &i_target, attr_proc_vrm_voffset_vdd); - DATABLOCK_GET_ATTR_CHECK_PROC(ATTR_PROC_VRM_VOFFSET_VCS, &i_target, attr_proc_vrm_voffset_vcs); - - DATABLOCK_GET_ATTR(ATTR_PM_RESONANT_CLOCK_FULL_CLOCK_SECTOR_BUFFER_FREQUENCY, NULL, attr_pm_resonant_clock_full_clock_sector_buffer_frequency); - DATABLOCK_GET_ATTR(ATTR_PM_RESONANT_CLOCK_LOW_BAND_LOWER_FREQUENCY, NULL, attr_pm_resonant_clock_low_band_lower_frequency); - DATABLOCK_GET_ATTR(ATTR_PM_RESONANT_CLOCK_LOW_BAND_UPPER_FREQUENCY, NULL, attr_pm_resonant_clock_low_band_upper_frequency); - DATABLOCK_GET_ATTR(ATTR_PM_RESONANT_CLOCK_HIGH_BAND_LOWER_FREQUENCY, NULL, attr_pm_resonant_clock_high_band_lower_frequency); - DATABLOCK_GET_ATTR(ATTR_PM_RESONANT_CLOCK_HIGH_BAND_UPPER_FREQUENCY, NULL, attr_pm_resonant_clock_high_band_upper_frequency); - - // Read array attribute - l_rc = FAPI_ATTR_GET(ATTR_CPM_INFLECTION_POINTS, &i_target, attr->attr_cpm_inflection_points); if (l_rc) break; - - for (i = 0; i < 16; i++) { - FAPI_INF("ATTR_CPM_INFLECTION_POINTS(%d) = 0x%08x %u",i, attr->attr_cpm_inflection_points[i], attr->attr_cpm_inflection_points[i]); - } - - // Read chip ec feature - DATABLOCK_GET_ATTR(ATTR_CHIP_EC_FEATURE_RESONANT_CLK_VALID, &i_target, attr_chip_ec_feature_resonant_clk_valid); - DATABLOCK_GET_ATTR(ATTR_PROC_EC_CORE_HANG_PULSE_BUG , &i_target, attr_proc_ec_core_hang_pulse_bug); - DATABLOCK_GET_ATTR(ATTR_CHIP_EC_FEATURE_IVRM_WINKLE_BUG , &i_target, attr_chip_ec_feature_ivrm_winkle_bug); + for (i = 0; i < 16; i++) + { + FAPI_INF("ATTR_CPM_INFLECTION_POINTS(%d) = 0x%08x %u",i, + attr->attr_cpm_inflection_points[i], attr->attr_cpm_inflection_points[i]); + } - // Read IVRM attributes - DATABLOCK_GET_ATTR(ATTR_PM_SYSTEM_IVRMS_ENABLED , NULL, attr_pm_system_ivrms_enabled); - DATABLOCK_GET_ATTR(ATTR_PM_SYSTEM_IVRM_VPD_MIN_LEVEL , NULL, attr_pm_system_ivrm_vpd_min_level); + // Read chip ec feature + DATABLOCK_GET_ATTR(ATTR_CHIP_EC_FEATURE_RESONANT_CLK_VALID, &i_target, + attr_chip_ec_feature_resonant_clk_valid); + DATABLOCK_GET_ATTR(ATTR_PROC_EC_CORE_HANG_PULSE_BUG , &i_target, + attr_proc_ec_core_hang_pulse_bug); + DATABLOCK_GET_ATTR(ATTR_CHIP_EC_FEATURE_IVRM_WINKLE_BUG , &i_target, + attr_chip_ec_feature_ivrm_winkle_bug); + + // Read IVRM attributes + DATABLOCK_GET_ATTR(ATTR_PM_SYSTEM_IVRMS_ENABLED , NULL, + attr_pm_system_ivrms_enabled); + DATABLOCK_GET_ATTR(ATTR_PM_SYSTEM_IVRM_VPD_MIN_LEVEL , NULL, + attr_pm_system_ivrm_vpd_min_level); + + // Read WOF attributes + DATABLOCK_GET_ATTR(ATTR_WOF_ENABLED , NULL, + attr_wof_enabled); + DATABLOCK_GET_ATTR(ATTR_TDP_RDP_CURRENT_FACTOR , &i_target, + attr_tdp_rdp_current_factor); + + // -------------------------------------------------------------- + // do basic attribute value checking and generate error if needed + // -------------------------------------------------------------- + + //check that dpll_divider is not 0 + if (attr->attr_proc_dpll_divider == 0) + { + FAPI_ERR("**** ERROR : Attribute ATTR_PROC_DPLL_DIVIDER = 0"); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_ATTR_DPLL_DIV_ERROR); + break; + } - // -------------------------------------------------------------- - // do basic attribute value checking and generate error if needed - // -------------------------------------------------------------- + // ---------------------------------------------------- + // Check Valid Frequency and Voltage Biasing Attributes + // - cannot have both up and down bias set + // ---------------------------------------------------- + if (attr->attr_freq_ext_bias_up > 0 && attr->attr_freq_ext_bias_down > 0) + { + FAPI_ERR("**** ERROR : Frequency bias up and down both defined"); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_FREQ_BIAS_ERROR); + break; + } - //check that dpll_divider is not 0 - if (attr->attr_proc_dpll_divider == 0) { - FAPI_ERR("**** ERROR : Attribute ATTR_PROC_DPLL_DIVIDER = 0"); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_ATTR_DPLL_DIV_ERROR); - break; - } + if (attr->attr_voltage_ext_vdd_bias_up > 0 + && attr->attr_voltage_ext_vdd_bias_down > 0) + { + FAPI_ERR("**** ERROR : External voltage bias up and down both defined"); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_EXT_VDD_VOLTAGE_BIAS_ERROR); + break; + } - // ---------------------------------------------------- - // Check Valid Frequency and Voltage Biasing Attributes - // - cannot have both up and down bias set - // ---------------------------------------------------- - if (attr->attr_freq_ext_bias_up > 0 && attr->attr_freq_ext_bias_down > 0) { - FAPI_ERR("**** ERROR : Frequency bias up and down both defined"); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_FREQ_BIAS_ERROR); - break; - } + if (attr->attr_voltage_ext_vcs_bias_up > 0 + && attr->attr_voltage_ext_vcs_bias_down > 0) + { + FAPI_ERR("**** ERROR : External voltage bias up and down both defined"); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_EXT_VCS_VOLTAGE_BIAS_ERROR); + break; + } - if (attr->attr_voltage_ext_vdd_bias_up > 0 && attr->attr_voltage_ext_vdd_bias_down > 0) { - FAPI_ERR("**** ERROR : External voltage bias up and down both defined"); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_EXT_VDD_VOLTAGE_BIAS_ERROR); - break; - } + if (attr->attr_voltage_int_vdd_bias_up > 0 + && attr->attr_voltage_int_vdd_bias_down > 0) + { + FAPI_ERR("**** ERROR : Internal voltage bias up and down both defined"); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_INT_VDD_VOLTAGE_BIAS_ERROR); + break; + } - if (attr->attr_voltage_ext_vcs_bias_up > 0 && attr->attr_voltage_ext_vcs_bias_down > 0) { - FAPI_ERR("**** ERROR : External voltage bias up and down both defined"); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_EXT_VCS_VOLTAGE_BIAS_ERROR); - break; - } + if (attr->attr_voltage_int_vcs_bias_up > 0 + && attr->attr_voltage_int_vcs_bias_down > 0) + { + FAPI_ERR("**** ERROR : Internal voltage bias up and down both defined"); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_INT_VCS_VOLTAGE_BIAS_ERROR); + break; + } - if (attr->attr_voltage_int_vdd_bias_up > 0 && attr->attr_voltage_int_vdd_bias_down > 0) { - FAPI_ERR("**** ERROR : Internal voltage bias up and down both defined"); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_INT_VDD_VOLTAGE_BIAS_ERROR); - break; - } + // print debug message if double biasing is enabled + if ( (attr->attr_voltage_ext_vdd_bias_up + attr->attr_voltage_ext_vdd_bias_down + > 0) && + (attr->attr_voltage_int_vdd_bias_up + attr->attr_voltage_int_vdd_bias_down > + 0) ) + { + FAPI_INF("Double Biasing enabled on external and internal VDD"); + } - if (attr->attr_voltage_int_vcs_bias_up > 0 && attr->attr_voltage_int_vcs_bias_down > 0) { - FAPI_ERR("**** ERROR : Internal voltage bias up and down both defined"); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_INT_VCS_VOLTAGE_BIAS_ERROR); - break; - } + if ( (attr->attr_voltage_ext_vcs_bias_up + attr->attr_voltage_ext_vcs_bias_down + > 0) && + (attr->attr_voltage_int_vcs_bias_up + attr->attr_voltage_int_vcs_bias_down > + 0) ) + { + FAPI_INF("Double Biasing enabled on external and internal VCS"); + } - // print debug message if double biasing is enabled - if ( (attr->attr_voltage_ext_vdd_bias_up + attr->attr_voltage_ext_vdd_bias_down > 0) && - (attr->attr_voltage_int_vdd_bias_up + attr->attr_voltage_int_vdd_bias_down > 0) ) - { - FAPI_INF("Double Biasing enabled on external and internal VDD"); - } + // check resonant clocking attribute values relative to each other + if (attr->attr_chip_ec_feature_resonant_clk_valid) + { + + if ( (attr->attr_pm_resonant_clock_low_band_lower_frequency > + attr->attr_pm_resonant_clock_low_band_upper_frequency) || + (attr->attr_pm_resonant_clock_low_band_upper_frequency > + attr->attr_pm_resonant_clock_high_band_lower_frequency) || + (attr->attr_pm_resonant_clock_high_band_lower_frequency > + attr->attr_pm_resonant_clock_high_band_upper_frequency) ) + { + const uint32_t &PM_RES_CLOCK_LOW_BAND_LOWER_FREQ = + attr->attr_pm_resonant_clock_low_band_lower_frequency; + const uint32_t &PM_RES_CLOCK_LOW_BAND_UPPER_FREQ = + attr->attr_pm_resonant_clock_low_band_upper_frequency; + const uint32_t &PM_RES_CLOCK_HIGH_BAND_LOWER_FREQ = + attr->attr_pm_resonant_clock_high_band_lower_frequency; + const uint32_t &PM_RES_CLOCK_HIGH_BAND_UPPER_FREQ = + attr->attr_pm_resonant_clock_high_band_upper_frequency; + FAPI_ERR("**** ERROR : Resonant clocking band attribute values are not in ascending order from low to high"); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_RESCLK_BAND_ERROR); + break; + } + } - if ( (attr->attr_voltage_ext_vcs_bias_up + attr->attr_voltage_ext_vcs_bias_down > 0) && - (attr->attr_voltage_int_vcs_bias_up + attr->attr_voltage_int_vcs_bias_down > 0) ) - { - FAPI_INF("Double Biasing enabled on external and internal VCS"); - } + // ------------------------------------------------------ + // do attribute default value setting if the are set to 0 + // ------------------------------------------------------ + if (attr->attr_freq_proc_refclock == 0) + { + attr->attr_freq_proc_refclock = 133; + FAPI_INF("Attribute value was 0 - setting to default value ATTR_FREQ_PROC_REFCLOCK = 133"); + } - // check resonant clocking attribute values relative to each other - if (attr->attr_chip_ec_feature_resonant_clk_valid) { - - if ( (attr->attr_pm_resonant_clock_low_band_lower_frequency > attr->attr_pm_resonant_clock_low_band_upper_frequency) || - (attr->attr_pm_resonant_clock_low_band_upper_frequency > attr->attr_pm_resonant_clock_high_band_lower_frequency) || - (attr->attr_pm_resonant_clock_high_band_lower_frequency > attr->attr_pm_resonant_clock_high_band_upper_frequency) ) { - const uint32_t &PM_RES_CLOCK_LOW_BAND_LOWER_FREQ = attr->attr_pm_resonant_clock_low_band_lower_frequency; - const uint32_t &PM_RES_CLOCK_LOW_BAND_UPPER_FREQ = attr->attr_pm_resonant_clock_low_band_upper_frequency; - const uint32_t &PM_RES_CLOCK_HIGH_BAND_LOWER_FREQ = attr->attr_pm_resonant_clock_high_band_lower_frequency; - const uint32_t &PM_RES_CLOCK_HIGH_BAND_UPPER_FREQ = attr->attr_pm_resonant_clock_high_band_upper_frequency; - FAPI_ERR("**** ERROR : Resonant clocking band attribute values are not in ascending order from low to high"); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_RESCLK_BAND_ERROR); - break; - } - } + if (attr->attr_proc_dpll_divider == 0) + { + attr->attr_proc_dpll_divider = 4; + FAPI_INF("Attribute value was 0 - setting to default value ATTR_PROC_DPLL_DIVIDER = 4"); + } - // ------------------------------------------------------ - // do attribute default value setting if the are set to 0 - // ------------------------------------------------------ - if (attr->attr_freq_proc_refclock == 0){ - attr->attr_freq_proc_refclock = 133; - FAPI_INF("Attribute value was 0 - setting to default value ATTR_FREQ_PROC_REFCLOCK = 133"); - } + if (attr->attr_pm_safe_frequency == 0) + { + attr->attr_pm_safe_frequency = attr->attr_boot_freq_mhz; + FAPI_INF("Attribute value was 0 - setting to default value ATTR_PM_SAFE_FREQUENCY = ATTR_BOOT_FREQ_MHZ"); + } - if (attr->attr_proc_dpll_divider == 0) { - attr->attr_proc_dpll_divider = 4; - FAPI_INF("Attribute value was 0 - setting to default value ATTR_PROC_DPLL_DIVIDER = 4"); - } + if (attr->attr_proc_r_loadline_vdd == 0) + { + attr->attr_proc_r_loadline_vdd = 570; + FAPI_INF("Attribute value was 0 - setting to default value ATTR_PROC_R_LOADLINE_VDD = 570"); + } - if (attr->attr_pm_safe_frequency == 0) { - attr->attr_pm_safe_frequency = attr->attr_boot_freq_mhz; - FAPI_INF("Attribute value was 0 - setting to default value ATTR_PM_SAFE_FREQUENCY = ATTR_BOOT_FREQ_MHZ"); - } + if (attr->attr_proc_r_loadline_vcs == 0) + { + attr->attr_proc_r_loadline_vcs = 570; + FAPI_INF("Attribute value was 0 - setting to default value ATTR_PROC_R_LOADLINE_VCS = 570"); + } - if (attr->attr_proc_r_loadline_vdd == 0) { - attr->attr_proc_r_loadline_vdd = 570; - FAPI_INF("Attribute value was 0 - setting to default value ATTR_PROC_R_LOADLINE_VDD = 570"); - } + if (attr->attr_proc_r_distloss_vdd == 0) + { + attr->attr_proc_r_distloss_vdd = 390; + FAPI_INF("Attribute value was 0 - setting to default value ATTR_PROC_R_DISTLOSS_VDD = 390"); + } - if (attr->attr_proc_r_loadline_vcs == 0) { - attr->attr_proc_r_loadline_vcs = 570; - FAPI_INF("Attribute value was 0 - setting to default value ATTR_PROC_R_LOADLINE_VCS = 570"); - } + if (attr->attr_proc_r_distloss_vcs == 0) + { + attr->attr_proc_r_distloss_vcs = 3500; + FAPI_INF("Attribute value was 0 - setting to default value ATTR_PROC_R_DISTLOSS_VCS = 3500"); + } - if (attr->attr_proc_r_distloss_vdd == 0) { - attr->attr_proc_r_distloss_vdd = 390; - FAPI_INF("Attribute value was 0 - setting to default value ATTR_PROC_R_DISTLOSS_VDD = 390"); - } + } + while(0); - if (attr->attr_proc_r_distloss_vcs == 0) { - attr->attr_proc_r_distloss_vcs = 3500; - FAPI_INF("Attribute value was 0 - setting to default value ATTR_PROC_R_DISTLOSS_VCS = 3500"); + return l_rc; } - } while(0); - - return l_rc; -} - /// ---------------------------------------------------------------- /// \brief Get #V data and put into array /// \param[in] i_target => Chip Target /// \param[inout] attr_mvpd_data => 5x5 array to hold the #V data /// ---------------------------------------------------------------- -ReturnCode proc_get_mvpd_data(const Target& i_target, - uint32_t attr_mvpd_data[PV_D][PV_W], - ivrm_mvpd_t *ivrm_mvpd, - uint8_t *present_chiplets, - uint8_t *functional_chiplets, - uint8_t *poundm_valid, - uint8_t *poundm_ver) -{ - ReturnCode l_rc; - std::vector<fapi::Target> l_exChiplets; - uint8_t l_functional = 0; - uint8_t * l_buffer = reinterpret_cast<uint8_t *>(malloc(512) ); - uint8_t * l_buffer_pdm = reinterpret_cast<uint8_t *>(malloc(512) ); - uint8_t * l_buffer_inc; - uint8_t * l_buffer_pdm_inc; - uint32_t l_bufferSize = 512; - uint32_t l_bufferSize_pdm = 512; - uint32_t l_record = 0; - uint32_t chiplet_mvpd_data[PV_D][PV_W]; - uint8_t j = 0; - uint8_t i = 0; - uint8_t ii = 0; - uint8_t first_chplt = 1; - uint8_t bucket_id = 0; - uint16_t cal_data[4]; - - do - { - // initialize - *present_chiplets = 0; - *functional_chiplets = 0; - - // ----------------------------------------------------------------- - // get list of chiplets and loop over each and get #V data from each - // ----------------------------------------------------------------- - // check that frequency is the same per chiplet - // for voltage, get the max for use for the chip - - l_rc = fapiGetChildChiplets (i_target, TARGET_TYPE_EX_CHIPLET, l_exChiplets, TARGET_STATE_PRESENT); - if (l_rc) { - FAPI_ERR("Error from fapiGetChildChiplets!"); - break; - } - - FAPI_INF("Number of EX chiplets present => %u", l_exChiplets.size()); - - for (j=0; j < l_exChiplets.size(); j++) { - *present_chiplets = 1; - l_bufferSize = 512; - l_bufferSize_pdm = 512; - uint8_t l_chipNum = 0xFF; - - l_rc = FAPI_ATTR_GET(ATTR_CHIP_UNIT_POS, &l_exChiplets[j], l_chipNum); - if (l_rc) { - FAPI_ERR("fapiGetAttribute of ATTR_CHIP_UNIT_POS error"); - break; - } - - // set l_record to appropriate lprx record (add core number to lrp0) - l_record = (uint32_t)fapi::MVPD_RECORD_LRP0 + l_chipNum; - - // clear out buffer to known value before calling fapiGetMvpdField - memset(l_buffer, 0, 512); - - // Get Chiplet MVPD data and put in chiplet_mvpd_data using accessor function - l_rc = fapiGetMvpdField((fapi::MvpdRecord)l_record, - fapi::MVPD_KEYWORD_PDV, - i_target, - l_buffer, - l_bufferSize); - if (!l_rc.ok()) { - FAPI_ERR("**** ERROR : Unexpected error encountered in fapiGetMvpdField"); - break; - } - - // check buffer size - if (l_bufferSize < PDV_BUFFER_SIZE) { - FAPI_ERR("**** ERROR : Wrong size buffer returned from fapiGetMvpdField for #V => %d", l_bufferSize ); - const uint32_t &BUFFER_SIZE = l_bufferSize; - const Target &CHIP_TARGET= i_target; - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PDV_BUFFER_SIZE_ERROR); - break; - } - - // clear array - memset(chiplet_mvpd_data, 0, sizeof(chiplet_mvpd_data)); - - // fill chiplet_mvpd_data 2d array with data iN buffer (skip first byte - bucket id) - #define UINT16_GET(__uint8_ptr) ((uint16_t)( ( (*((const uint8_t *)(__uint8_ptr)) << 8) | *((const uint8_t *)(__uint8_ptr) + 1) ) )) - - // use copy of allocated buffer pointer to increment through buffer - l_buffer_inc = l_buffer; - - bucket_id = *l_buffer_inc; - l_buffer_inc++; - - FAPI_INF("#V chiplet = %u bucket id = %u", l_chipNum, bucket_id); - - for (i=0; i<=4; i++) { - - for (ii=0; ii<=4; ii++) { - chiplet_mvpd_data[i][ii] = (uint32_t) UINT16_GET(l_buffer_inc); - FAPI_INF("#V data = 0x%04X %-6d", chiplet_mvpd_data[i][ii], chiplet_mvpd_data[i][ii]); - // increment to next MVPD value in buffer - l_buffer_inc+= 2; - } - } - - // perform data validity checks on this #V data before proceeding to use it - l_rc = proc_chk_valid_poundv(i_target ,chiplet_mvpd_data, l_chipNum, bucket_id); - if (l_rc) break; + ReturnCode proc_get_mvpd_data(const Target& i_target, + AttributeList *i_attr, + uint32_t attr_mvpd_data[PV_D][PV_W], + uint32_t *valid_pdv_points, + ivrm_mvpd_t *ivrm_mvpd, + uint8_t *present_chiplets, + uint8_t *functional_chiplets, + uint8_t *poundm_valid, + uint8_t *poundm_ver) + { + ReturnCode l_rc; + std::vector<fapi::Target> l_exChiplets; + uint8_t l_functional = 0; + uint8_t * l_buffer = reinterpret_cast<uint8_t *>(malloc(PDV_BUFFER_ALLOC) ); + uint8_t * l_buffer_pdm = reinterpret_cast<uint8_t *>(malloc(PDM_BUFFER_ALLOC) ); + uint8_t * l_buffer_inc; + uint8_t * l_buffer_pdm_inc; + uint32_t l_bufferSize = 512; + uint32_t l_bufferSize_pdm = 512; + uint32_t l_record = 0; + uint32_t chiplet_mvpd_data[PV_D][PV_W]; + uint8_t j = 0; + uint8_t i = 0; + uint8_t ii = 0; + uint8_t first_chplt = 1; + uint8_t bucket_id = 0; + uint16_t cal_data[POUNDM_MEASUREMENTS_PER_POINT]; + + + do + { + // initialize + *present_chiplets = 0; + *functional_chiplets = 0; + + // ----------------------------------------------------------------- + // get list of chiplets and loop over each and get #V data from each + // ----------------------------------------------------------------- + // check that frequency is the same per chiplet + // for voltage, get the max for use for the chip + + l_rc = fapiGetChildChiplets (i_target, TARGET_TYPE_EX_CHIPLET, l_exChiplets, + TARGET_STATE_PRESENT); + + if (l_rc) + { + FAPI_ERR("Error from fapiGetChildChiplets!"); + break; + } - // on first chiplet put each bucket's data into attr_mvpd_voltage_control - if (first_chplt) { + *present_chiplets = l_exChiplets.size(); + FAPI_INF("Number of EX chiplets present => %u", *present_chiplets); + + for (j=0; j < l_exChiplets.size(); j++) + { + + l_bufferSize = 512; + l_bufferSize_pdm = 512; + uint8_t l_chipNum = 0xFF; + + l_rc = FAPI_ATTR_GET(ATTR_CHIP_UNIT_POS, &l_exChiplets[j], l_chipNum); + + if (l_rc) + { + FAPI_ERR("fapiGetAttribute of ATTR_CHIP_UNIT_POS error"); + break; + } + + // set l_record to appropriate lprx record (add core number to lrp0) + l_record = (uint32_t)fapi::MVPD_RECORD_LRP0 + l_chipNum; + + // clear out buffer to known value before calling fapiGetMvpdField + memset(l_buffer, 0, 512); + + // Get Chiplet MVPD data and put in chiplet_mvpd_data using accessor function + l_rc = fapiGetMvpdField((fapi::MvpdRecord)l_record, + fapi::MVPD_KEYWORD_PDV, + i_target, + l_buffer, + l_bufferSize); + + if (!l_rc.ok()) + { + FAPI_ERR("**** ERROR : Unexpected error encountered in fapiGetMvpdField"); + break; + } + + // check buffer size + if (l_bufferSize < PDV_BUFFER_SIZE) + { + FAPI_ERR("**** ERROR : Wrong size buffer returned from fapiGetMvpdField for #V => %d", + l_bufferSize ); + const uint32_t &BUFFER_SIZE = l_bufferSize; + const Target &CHIP_TARGET= i_target; + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PDV_BUFFER_SIZE_ERROR); + break; + } + + // clear array + memset(chiplet_mvpd_data, 0, sizeof(chiplet_mvpd_data)); + + // fill chiplet_mvpd_data 2d array with data iN buffer (skip first byte - bucket id) +#define UINT16_GET(__uint8_ptr) ((uint16_t)( ( (*((const uint8_t *)(__uint8_ptr)) << 8) | *((const uint8_t *)(__uint8_ptr) + 1) ) )) + + // use copy of allocated buffer pointer to increment through buffer + l_buffer_inc = l_buffer; + + bucket_id = *l_buffer_inc; + l_buffer_inc++; + + FAPI_INF("#V chiplet = %u bucket id = %u", l_chipNum, bucket_id); + + for (i=0; i<=4; i++) + { + + for (ii=0; ii<=4; ii++) + { + chiplet_mvpd_data[i][ii] = (uint32_t) UINT16_GET(l_buffer_inc); + FAPI_INF("#V data = 0x%04X %-6d", chiplet_mvpd_data[i][ii], + chiplet_mvpd_data[i][ii]); + // increment to next MVPD value in buffer + l_buffer_inc+= 2; + } + } + + // perform data validity checks on this #V data before proceeding to use it + l_rc = proc_chk_valid_poundv( i_target, + i_attr, + chiplet_mvpd_data, + valid_pdv_points, + l_chipNum, + bucket_id); + + if (l_rc == RC_PROCPM_PSTATE_DATABLOCK_PDV_ZERO_DATA_UT_ERROR) + { + // Disable WOF + i_attr->attr_wof_enabled = 0; + } + else if (l_rc) + { + break; + } + + // on first chiplet put each bucket's data into attr_mvpd_voltage_control + if (first_chplt) + { + + for (i=0; i<=4; i++) + { + + for (ii=0; ii<=4; ii++) + { + attr_mvpd_data[i][ii] = chiplet_mvpd_data[i][ii]; + } + } + + first_chplt = 0; + } + else + { + // on subsequent chiplets, check that frequencies are same for each operating point for each chiplet + if ( (attr_mvpd_data[0][0] != chiplet_mvpd_data[0][0]) || + (attr_mvpd_data[1][0] != chiplet_mvpd_data[1][0]) || + (attr_mvpd_data[2][0] != chiplet_mvpd_data[2][0]) || + (attr_mvpd_data[3][0] != chiplet_mvpd_data[3][0]) || + (attr_mvpd_data[4][0] != chiplet_mvpd_data[4][0]) ) + { + const uint32_t &ATTR_MVPD_DATA_0 = attr_mvpd_data[0][0]; + const uint32_t &ATTR_MVPD_DATA_1 = attr_mvpd_data[1][0]; + const uint32_t &ATTR_MVPD_DATA_2 = attr_mvpd_data[2][0]; + const uint32_t &ATTR_MVPD_DATA_3 = attr_mvpd_data[3][0]; + const uint32_t &ATTR_MVPD_DATA_4 = attr_mvpd_data[4][0]; + FAPI_ERR("**** ERROR : frequencies are not the same for each operating point for each chiplet"); + const Target &CHIP_TARGET= i_target; + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_MVPD_CHIPLET_VOLTAGE_NOT_EQUAL); + break; + } + } + + // check each bucket for max voltage and if max, put bucket's data into attr_mvpd_voltage_control + for (i=0; i <= 4; i++) + { + + if (attr_mvpd_data[i][1] < chiplet_mvpd_data[i][1]) + { + attr_mvpd_data[i][0] = chiplet_mvpd_data[i][0]; + attr_mvpd_data[i][1] = chiplet_mvpd_data[i][1]; + attr_mvpd_data[i][2] = chiplet_mvpd_data[i][2]; + attr_mvpd_data[i][3] = chiplet_mvpd_data[i][3]; + attr_mvpd_data[i][4] = chiplet_mvpd_data[i][4]; + } + } + + // -------------------------------------------- + // Process #M Data + // -------------------------------------------- + + // Determine if present chiplet is functional + l_rc = FAPI_ATTR_GET(ATTR_FUNCTIONAL, &l_exChiplets[j], l_functional); + + if (l_rc) + { + FAPI_ERR("fapiGetAttribute of ATTR_FUNCTIONAL error"); + break; + } + + if ( l_functional ) + { + *functional_chiplets = 1; + + // clear out buffer to known value before calling fapiGetMvpdField + memset(l_buffer_pdm, 0, PDM_BUFFER_ALLOC); + + // Get Chiplet #M MVPD data + l_rc = fapiGetMvpdField((fapi::MvpdRecord)l_record, + fapi::MVPD_KEYWORD_PDM, + i_target, + l_buffer_pdm, + l_bufferSize_pdm); + + if (!l_rc.ok()) + { + FAPI_INF("**** Warning : Unexpected error encountered in fapiGetMvpdField - IVRMs will not be enabled"); + *poundm_valid = 0; + } + + // check buffer size + if (l_bufferSize_pdm < PDM_BUFFER_SIZE) + { + FAPI_ERR("**** ERROR : Wrong size buffer returned from fapiGetMvpdField for #M from LRP%u => %d vs expected %d", + l_chipNum, l_bufferSize_pdm, PDM_BUFFER_SIZE); + const uint32_t &BUFFER_SIZE = l_bufferSize; + const Target &CHIP_TARGET= i_target; + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PDM_BUFFER_SIZE_ERROR); + break; + } + + // use copy of allocated buffer pointer to increment through buffer + l_buffer_pdm_inc = l_buffer_pdm; + + // get #M version and advance pointer 1-byte to beginning of #M data + *poundm_ver = *l_buffer_pdm_inc; + ivrm_mvpd->header.version = *poundm_ver ; + l_buffer_pdm_inc++; + + // loop over 13 entries of #M data with 4 measurements per entry + FAPI_INF("#M chiplet = %u version = %u", l_chipNum, *poundm_ver); + + for (i=0; i < POUNDM_POINTS; i++) + { + + for (ii=0; ii<POUNDM_MEASUREMENTS_PER_POINT; ii++) + { + cal_data[ii] = UINT16_GET(l_buffer_pdm_inc); + + if (*poundm_ver == 2) + { + l_buffer_pdm_inc+= 4; + } + else + { + l_buffer_pdm_inc+= 2; + } + + } + + ivrm_mvpd->data.ex[j].point[i].gate_voltage = cal_data[0]; + ivrm_mvpd->data.ex[j].point[i].drain_voltage = cal_data[1]; + ivrm_mvpd->data.ex[j].point[i].source_voltage = cal_data[2]; + ivrm_mvpd->data.ex[j].point[i].drain_current = cal_data[3]; + + FAPI_INF("#M data (hex & dec) = 0x%04x 0x%04x 0x%04x 0x%04x %5u %5u %5u %5u", + cal_data[0], cal_data[1], cal_data[2], cal_data[3], cal_data[0], cal_data[1], + cal_data[2], cal_data[3]); + + // #M validity check - not valid if measurements are 0 (exception : cal_data[0](Vg) can be 0) + if (cal_data[1] == 0 || cal_data[2] == 0 || cal_data[3] == 0 ) + { + FAPI_INF("**** Warning : #M has zero valued measurements - IVRMs will not be enabled"); + *poundm_valid = 0; + } + + } + + // set number of samples + ivrm_mvpd->data.ex[j].point_valid = POUNDM_POINTS; + } // end functional + + } // end for loop - for (i=0; i<=4; i++) { - for (ii=0; ii<=4; ii++) { - attr_mvpd_data[i][ii] = chiplet_mvpd_data[i][ii]; - } - } - first_chplt = 0; - } - else { - // on subsequent chiplets, check that frequencies are same for each operating point for each chiplet - if ( (attr_mvpd_data[0][0] != chiplet_mvpd_data[0][0]) || - (attr_mvpd_data[1][0] != chiplet_mvpd_data[1][0]) || - (attr_mvpd_data[2][0] != chiplet_mvpd_data[2][0]) || - (attr_mvpd_data[3][0] != chiplet_mvpd_data[3][0]) || - (attr_mvpd_data[4][0] != chiplet_mvpd_data[4][0]) ) { - const uint32_t &ATTR_MVPD_DATA_0 = attr_mvpd_data[0][0]; - const uint32_t &ATTR_MVPD_DATA_1 = attr_mvpd_data[1][0]; - const uint32_t &ATTR_MVPD_DATA_2 = attr_mvpd_data[2][0]; - const uint32_t &ATTR_MVPD_DATA_3 = attr_mvpd_data[3][0]; - const uint32_t &ATTR_MVPD_DATA_4 = attr_mvpd_data[4][0]; - FAPI_ERR("**** ERROR : frequencies are not the same for each operating point for each chiplet"); - const Target &CHIP_TARGET= i_target; - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_MVPD_CHIPLET_VOLTAGE_NOT_EQUAL); - break; } - } + while(0); - // check each bucket for max voltage and if max, put bucket's data into attr_mvpd_voltage_control - for (i=0; i <= 4; i++) { + free (l_buffer); + free (l_buffer_pdm); - if (attr_mvpd_data[i][1] < chiplet_mvpd_data[i][1]) { - attr_mvpd_data[i][0] = chiplet_mvpd_data[i][0]; - attr_mvpd_data[i][1] = chiplet_mvpd_data[i][1]; - attr_mvpd_data[i][2] = chiplet_mvpd_data[i][2]; - attr_mvpd_data[i][3] = chiplet_mvpd_data[i][3]; - attr_mvpd_data[i][4] = chiplet_mvpd_data[i][4]; - } - } - - // -------------------------------------------- - // Process #M Data - // -------------------------------------------- - - // Determine if present chiplet is functional - l_rc = FAPI_ATTR_GET(ATTR_FUNCTIONAL, &l_exChiplets[j], l_functional); - if (l_rc) { - FAPI_ERR("fapiGetAttribute of ATTR_FUNCTIONAL error"); - break; - } - - if ( l_functional ) { - *functional_chiplets = 1; - - // clear out buffer to known value before calling fapiGetMvpdField - memset(l_buffer_pdm, 0, 512); - - // Get Chiplet #M MVPD data - l_rc = fapiGetMvpdField((fapi::MvpdRecord)l_record, - fapi::MVPD_KEYWORD_PDM, - i_target, - l_buffer_pdm, - l_bufferSize_pdm); - if (!l_rc.ok()) { - FAPI_INF("**** Warning : Unexpected error encountered in fapiGetMvpdField - IVRMs will not be enabled"); - *poundm_valid = 0; - } - - // check buffer size - if (l_bufferSize_pdm < PDM_BUFFER_SIZE) { - FAPI_ERR("**** ERROR : Wrong size buffer returned from fapiGetMvpdField for #M => %d", l_bufferSize_pdm ); - const uint32_t &BUFFER_SIZE = l_bufferSize; - const Target &CHIP_TARGET= i_target; - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PDM_BUFFER_SIZE_ERROR); - break; - } + return l_rc; - // use copy of allocated buffer pointer to increment through buffer - l_buffer_pdm_inc = l_buffer_pdm; + } // end proc_get_mvpd_data - // get #M version and advance pointer 1-byte to beginning of #M data - *poundm_ver = *l_buffer_pdm_inc; - ivrm_mvpd->header.version = *poundm_ver ; - l_buffer_pdm_inc++; - - // loop over 13 entries of #M data with 4 measurements per entry - FAPI_INF("#M chiplet = %u version = %u", l_chipNum, *poundm_ver); - - for (i=0; i < POUNDM_POINTS; i++) { - - for (ii=0; ii<4; ii++) { - cal_data[ii] = UINT16_GET(l_buffer_pdm_inc); - - if (*poundm_ver == 2) - l_buffer_pdm_inc+= 4; - else - l_buffer_pdm_inc+= 2; - - } - - ivrm_mvpd->data.ex[j].point[i].gate_voltage = cal_data[0]; - ivrm_mvpd->data.ex[j].point[i].drain_voltage = cal_data[1]; - ivrm_mvpd->data.ex[j].point[i].source_voltage = cal_data[2]; - ivrm_mvpd->data.ex[j].point[i].drain_current = cal_data[3]; - - FAPI_INF("#M data (hex & dec) = 0x%04x 0x%04x 0x%04x 0x%04x %5u %5u %5u %5u", cal_data[0], cal_data[1], cal_data[2], cal_data[3], cal_data[0], cal_data[1], cal_data[2], cal_data[3]); - - // #M validity check - not valid if measurements are 0 (exception : cal_data[0](Vg) can be 0) - if (cal_data[1] == 0 || cal_data[2] == 0 || cal_data[3] == 0 ) - { - FAPI_INF("**** Warning : #M has zero valued measurements - IVRMs will not be enabled"); - *poundm_valid = 0; - } +/// ---------------------------------------------------------------- +/// \brief Get IQ (IDDQ) data and put into array +/// \param[in] i_target => Chip Target +/// \param[inout] attr_mvpd_iddq => 24 x 16 array to hold the IQ data +/// ---------------------------------------------------------------- + ReturnCode proc_get_mvpd_iddq(const Target& i_target, + PstateSuperStructure *pss) + { + ReturnCode l_rc; + uint8_t * l_buffer_iq = reinterpret_cast<uint8_t *>(malloc(IQ_BUFFER_ALLOC)); + uint8_t * l_buffer_iq_c = reinterpret_cast<uint8_t *>(malloc(IQ_BUFFER_ALLOC)); + + uint8_t * l_buffer_iq_inc; + uint32_t l_bufferSize_iq = IQ_BUFFER_ALLOC; + uint32_t l_record = 0; + uint32_t l_lrp_record = 0; + IddqReading * l_iddq_reading; + uint32_t c = 0; + + + const uint8_t vdd_measurement_order[LRP_IDDQ_RECORDS] = + CORE_IDDQ_MEASUREMENTS_ORDER; + const char * core_measurement_str[LRP_IDDQ_RECORDS] = + CORE_IDDQ_MEASUREMENT_VOLTAGES; + const uint8_t vcs_measurement_order[LRP_IDDQ_RECORDS] = + CORE_IDDQ_MEASUREMENTS_ORDER; + const uint8_t core_validity_check[LRP_IDDQ_RECORDS] = + CORE_IDDQ_VALIDITY_CHECK; + const uint8_t core_second_reading_valid[LRP_IDDQ_RECORDS] = + CORE_IDDQ_VALID_SECOND; + + const char * chip_measurement_str[CRP_IDDQ_RECORDS] = + CHIP_IDDQ_MEASUREMENT_VOLTAGES; + const uint8_t vio_measurement_order[CRP_IDDQ_RECORDS] = + CHIP_IDDQ_MEASUREMENTS_ORDER; + + + // -------------------------------------------- + // Process IQ (IDD) Data + // -------------------------------------------- + + // This extraction is not done based on functional or present EX chiplets + // as the chip level IDDQ values are stored in LRPx records as matter of + // available data storage locations; they are NOT associated with the + // EX chiplets themselves. + + // The chip level readings are stored as follows: + // LRP 1 1 Vdd 0.90 Raw + // LRP 1 2 Vdd 0.90 Temp corrected + // LRP 1 3 Vcs 0.90 Raw + // LRP 1 4 Vcs 0.90 Temp corrected + // LRP 2 1 Vdd 1.00 Raw + // LRP 2 2 Vdd 1.00 Temp corrected + // LRP 2 3 Vcs 1.00 Raw + // LRP 2 4 Vcs 1.00 Temp corrected + // LRP 3 1 Vdd 1.10 Raw + // LRP 3 2 Vdd 1.10 Temp corrected + // LRP 3 3 Vcs 1.10 Raw + // LRP 3 4 Vcs 1.10 Temp corrected + // LRP 4 1 Vdd 1.20 Raw + // LRP 4 2 Vdd 1.20 Temp corrected + // LRP 4 3 Vcs 1.20 Raw + // LRP 4 4 Vcs 1.20 Temp corrected + // LRP 5 1 Vdd 1.25 Raw + // LRP 5 2 Vdd 1.25 Temp corrected + // LRP 5 3 Vcs 1.25 Raw + // LRP 5 4 Vcs 1.25 Temp corrected + // LRP 6 1 Vdd 0.80 Raw + // LRP 6 2 Vdd 0.80 Temp corrected + // CRP 0 1 Vio 1.10 Raw + // CRP 0 2 Vio 1.10 Temp corrected + // + // Note: Vcs never gets to 0.80V. Therefore LRP 6 does not have Vcss. + // + // Each entry is 2 bytes. The values are in 10mA units; this allow for a + // maximum value of 655.36A represented. + // + // Temp corrected value = Raw value * (1.25^((60C - OCTS_avg_temp)/10) + // + // Buffer size needed is, at minimum 2B x 24 = 48B. + + do + { + FAPI_INF("Processing LRPx records for IDDQ keywords"); + for (c = 0; c < LRP_IDDQ_RECORDS; ++c) + { + // clear out buffer to known value before calling fapiGetMvpdField + memset(l_buffer_iq, 0, IQ_BUFFER_ALLOC); + + l_lrp_record = c+1; + + // set l_record to appropriate lprx record (add core number to lrp0) + // Note: Index in the loop are zero origin while the LRP records start at 1 + l_record = (uint32_t)fapi::MVPD_RECORD_LRP0 + l_lrp_record; + + // Get Chiplet IQ MVPD data from the LRP recoreds + l_rc = fapiGetMvpdField((fapi::MvpdRecord)l_record, + fapi::MVPD_KEYWORD_IQ, + i_target, + l_buffer_iq, + l_bufferSize_iq); + + if (!l_rc.ok()) + { + FAPI_ERR("**** Error: fapiGetMvpdField from LRP%u", l_lrp_record); + const uint32_t &CHIPLET_NUMBER = vdd_measurement_order[c]; + const Target &CHIP_TARGET= i_target; + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_IQ_MVPD_ERROR); + break; + } + + // check buffer size + if (l_bufferSize_iq < IQ_BUFFER_SIZE) + { + FAPI_ERR("**** ERROR : Wrong size buffer returned from fapiGetMvpdField for IQ => %d", + l_bufferSize_iq ); + const uint32_t &BUFFER_SIZE = l_bufferSize_iq; + const Target &CHIP_TARGET= i_target; + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_IQ_BUFFER_SIZE_ERROR); + break; + } + + // Initialize the incrementing pointer + l_buffer_iq_inc = l_buffer_iq; + + // get IQ version and advance pointer 1-byte to beginning of IQ data + uint8_t iq_ver = *l_buffer_iq_inc; + pss->iddq.iddq_version = iq_ver ; + FAPI_INF(" LRP%d: IDDQ Version Number = %u", l_lrp_record, + iq_ver); + + // Increment pointer beyond the 1B version number to the first of the + // reading data + l_buffer_iq_inc++; + + l_iddq_reading = reinterpret_cast<IddqReading*>(l_buffer_iq_inc); + pss->iddq.iddq_vdd[vdd_measurement_order[c]].value = + revle32((*l_iddq_reading).value); + + FAPI_INF(" IQ VDD measurement in LRP%d (hex & dec) = 0x%04X %5d (raw), 0x%04X %5d (temp corrected)", + l_lrp_record, + pss->iddq.iddq_vdd[vdd_measurement_order[c]].fields.iddq_raw_value, + pss->iddq.iddq_vdd[vdd_measurement_order[c]].fields.iddq_raw_value, + pss->iddq.iddq_vdd[vdd_measurement_order[c]].fields.iddq_corrected_value, + pss->iddq.iddq_vdd[vdd_measurement_order[c]].fields.iddq_corrected_value); + + // Check for reading validity + // Applies to LRP1-5 content for all versions + // Checking LRP6 (VDD = 0.8V) will only produce a warning but will not fail + + // Assume that the 0.80V readings are valid. If they turn out to be zeros, + // clear the flag in the Pstate Options vector. + + pss->gpst.options.options = revle32(revle32(pss->gpst.options.options) + | + PSTATE_IDDQ_0P80V_VALID); + + if (revle16(l_iddq_reading->fields.iddq_raw_value) == 0) + { + FAPI_INF("**** Warning : IQ VDD measurement @ %s has zero valued measurement", + core_measurement_str[c]); + + if (core_validity_check[c]) + { + FAPI_ERR("**** Error : IQ measurement was 0 when expected to be non-zero"); + const uint16_t &RAW_VALUE = revle16(l_iddq_reading->fields.iddq_raw_value); + const uint32_t &LRP_NUMBER = l_lrp_record; + const Target &CHIP_TARGET= i_target; + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_IQ_INVALID_VDD_ERROR); + break; + } + // The only reading that might not be valid is 0.8V. If the readings + // are zero and the valitity check is off, then clear the 0.80 valid + // flag. + else + { + pss->gpst.options.options = revle32(revle32(pss->gpst.options.options) + & + PSTATE_IDDQ_0P80V_INVALID); + + } + } + + if (core_second_reading_valid[c]) + { + FAPI_DBG(" Second reading valid for LRP%d", l_lrp_record); + + l_buffer_iq_inc += sizeof(IddqReading); + + l_iddq_reading = reinterpret_cast<IddqReading*>(l_buffer_iq_inc); + pss->iddq.iddq_vcs[vcs_measurement_order[c]].value = + revle32((*l_iddq_reading).value); + + FAPI_INF(" IQ VCS measurement in LRP%d (hex & dec) = 0x%04X %5d (raw), 0x%04X %5d (temp corrected)", + l_lrp_record, + pss->iddq.iddq_vcs[vcs_measurement_order[c]].fields.iddq_raw_value, + pss->iddq.iddq_vcs[vcs_measurement_order[c]].fields.iddq_raw_value, + pss->iddq.iddq_vcs[vcs_measurement_order[c]].fields.iddq_corrected_value, + pss->iddq.iddq_vcs[vcs_measurement_order[c]].fields.iddq_corrected_value); + + if (l_iddq_reading->fields.iddq_raw_value == 0) + { + FAPI_INF("**** Warning : IQ VDD measurement @ %s has zero valued measurement", + core_measurement_str[c]); + const uint16_t &RAW_VALUE = revle16(l_iddq_reading->fields.iddq_raw_value); + const uint32_t &LRP_NUMBER = c; + const Target &CHIP_TARGET= i_target; + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_IQ_INVALID_VCS_ERROR); + break; + } + } + + } // for LRP records + + // Error out chck + if(!l_rc.ok()) + { + break; + } + + + FAPI_INF("Processing CRP records for IDDQ keywords"); + for (c = 0; c < CRP_IDDQ_RECORDS; ++c) + { + // clear out buffer to known value before calling fapiGetMvpdField + memset(l_buffer_iq_c, 0, IQ_BUFFER_ALLOC); + + // set l_record to appropriate cprx record + l_record = (uint32_t)fapi::MVPD_RECORD_CRP0; + l_bufferSize_iq = IQ_BUFFER_ALLOC; // @todo? + + FAPI_DBG("fapiGetMvpdField(record %X, keyword %X, iq %p, size %d)", l_record, + (uint32_t)fapi::MVPD_KEYWORD_IQ, + l_buffer_iq_c, + l_bufferSize_iq); + + // Get Chip IQ MVPD data from the CRPx records + l_rc = fapiGetMvpdField((fapi::MvpdRecord)l_record, + fapi::MVPD_KEYWORD_IQ, + i_target, + l_buffer_iq_c, + l_bufferSize_iq); + if (!l_rc.ok()) + { + FAPI_ERR("**** Error: fapiGetMvpdField from CRP%u with size %d into buffer sized at %d and rc = %X", + c, l_bufferSize_iq, IQ_BUFFER_ALLOC, (uint32_t)l_rc); + const uint32_t &CHIPLET_NUMBER = c; + const Target &CHIP_TARGET= i_target; + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_IQ_MVPD_ERROR); + break; + } + + // check buffer size + if (l_bufferSize_iq < IQ_BUFFER_SIZE) + { + FAPI_ERR("**** ERROR : Wrong size buffer returned from fapiGetMvpdField for IQ => %d", l_bufferSize_iq ); + const uint32_t &BUFFER_SIZE = l_bufferSize_iq; + const Target &CHIP_TARGET= i_target; + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_IQ_BUFFER_SIZE_ERROR); + break; + } + + // use copy of allocated buffer pointer to increment through buffer + l_buffer_iq_inc = l_buffer_iq_c; + + // get IQ version and advance pointer 1-byte to beginning of IQ data + uint8_t iq_ver = *l_buffer_iq_inc; + pss->iddq.iddq_version = iq_ver ; + FAPI_INF(" CRP0: IDDQ Version Number = %u", iq_ver); + l_buffer_iq_inc++; + + l_iddq_reading = reinterpret_cast<IddqReading*>(l_buffer_iq_inc); + pss->iddq.iddq_vio[vio_measurement_order[c]].value = + revle32((*l_iddq_reading).value); + + FAPI_INF(" IQ VIO measurement (hex & dec) = 0x%04x %5x (raw), 0x%04x %5x (temp corrected)", + pss->iddq.iddq_vio[c].fields.iddq_raw_value, + pss->iddq.iddq_vio[c].fields.iddq_raw_value, + pss->iddq.iddq_vio[c].fields.iddq_corrected_value, + pss->iddq.iddq_vio[c].fields.iddq_corrected_value); + + if (revle16(l_iddq_reading->fields.iddq_raw_value) == 0) + { + FAPI_ERR("IQ VIO measurement @ %s has zero valued measurement", + chip_measurement_str[c]); + const uint16_t &RAW_VALUE = l_iddq_reading->fields.iddq_raw_value ; + const Target &CHIP_TARGET= i_target; + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_IQ_INVALID_VIO_ERROR); + break; + } + + } // for CRP records } + while(0); - // set number of samples to 13 - ivrm_mvpd->data.ex[j].point_valid = POUNDM_POINTS; - } // end functional - - } // end for loop + // Free up memory buffer + free(l_buffer_iq); +// free(l_buffer_iq_c); - } while(0); + return l_rc; - free (l_buffer); - free (l_buffer_pdm); + } // proc_get_mvdp_iddq - return l_rc; -} // end proc_get_mvpd_data /// --------------------------------------------------------------------------- @@ -989,44 +1612,59 @@ ReturnCode proc_get_mvpd_data(const Target& i_target, /// \param[inout] * volt_int_vdd_bias => pointer to internal vdd bias /// \param[inout] * volt_int_vcs_bias => pointer to internal vcs bias /// --------------------------------------------------------------------------- -ReturnCode proc_get_extint_bias(uint32_t attr_mvpd_data[PV_D][PV_W], - const AttributeList *attr, - double *volt_int_vdd_bias, - double *volt_int_vcs_bias) -{ - ReturnCode l_rc; - int i = 0; - double freq_bias = 1.0; - double volt_ext_vdd_bias = 1.0; - double volt_ext_vcs_bias = 1.0; - - // -------------------------------------------------------------------------- - // Apply specified Frequency and Voltage Biasing to attr_mvpd_voltage_control - // - at least one bias value is guaranteed to be 0 - // - convert freq/voltage to double - // - compute biased freq/voltage and round - // - convert back to integer - // -------------------------------------------------------------------------- - - freq_bias = 1.0 + (BIAS_PCT_UNIT * (double)attr->attr_freq_ext_bias_up) - (BIAS_PCT_UNIT * (double)attr->attr_freq_ext_bias_down); - volt_ext_vdd_bias = 1.0 + (BIAS_PCT_UNIT * (double)attr->attr_voltage_ext_vdd_bias_up) - (BIAS_PCT_UNIT * (double)attr->attr_voltage_ext_vdd_bias_down); - volt_ext_vcs_bias = 1.0 + (BIAS_PCT_UNIT * (double)attr->attr_voltage_ext_vcs_bias_up) - (BIAS_PCT_UNIT * (double)attr->attr_voltage_ext_vcs_bias_down); - *volt_int_vdd_bias = 1.0 + (BIAS_PCT_UNIT * (double)attr->attr_voltage_int_vdd_bias_up) - (BIAS_PCT_UNIT * (double)attr->attr_voltage_int_vdd_bias_down); - *volt_int_vcs_bias = 1.0 + (BIAS_PCT_UNIT * (double)attr->attr_voltage_int_vcs_bias_up) - (BIAS_PCT_UNIT * (double)attr->attr_voltage_int_vcs_bias_down); - - // loop over each operating point - for (i=0; i <= 4; i++) { - attr_mvpd_data[i][0] = (uint32_t) ((( (double)attr_mvpd_data[i][0]) * freq_bias) + 0.5); - attr_mvpd_data[i][1] = (uint32_t) ((( (double)attr_mvpd_data[i][1]) * volt_ext_vdd_bias) + 0.5); - attr_mvpd_data[i][3] = (uint32_t) ((( (double)attr_mvpd_data[i][3]) * volt_ext_vcs_bias) + 0.5); - } - - FAPI_INF("BIAS freq = %f", freq_bias); - FAPI_INF("BIAS vdd ext = %f vcs ext = %f", volt_ext_vdd_bias, volt_ext_vcs_bias); - FAPI_INF("BIAS vdd int = %f vcs int = %f", *volt_int_vdd_bias, *volt_int_vcs_bias); - - return l_rc; -} // end proc_get_extint_bias + ReturnCode proc_get_extint_bias(uint32_t attr_mvpd_data[PV_D][PV_W], + const AttributeList *attr, + double *volt_int_vdd_bias, + double *volt_int_vcs_bias) + { + ReturnCode l_rc; + int i = 0; + double freq_bias = 1.0; + double volt_ext_vdd_bias = 1.0; + double volt_ext_vcs_bias = 1.0; + + // -------------------------------------------------------------------------- + // Apply specified Frequency and Voltage Biasing to attr_mvpd_voltage_control + // - at least one bias value is guaranteed to be 0 + // - convert freq/voltage to double + // - compute biased freq/voltage and round + // - convert back to integer + // -------------------------------------------------------------------------- + + freq_bias = 1.0 + (BIAS_PCT_UNIT * (double)attr->attr_freq_ext_bias_up) + - (BIAS_PCT_UNIT * (double)attr->attr_freq_ext_bias_down); + volt_ext_vdd_bias = 1.0 + (BIAS_PCT_UNIT * (double) + attr->attr_voltage_ext_vdd_bias_up) - (BIAS_PCT_UNIT * (double) + attr->attr_voltage_ext_vdd_bias_down); + volt_ext_vcs_bias = 1.0 + (BIAS_PCT_UNIT * (double) + attr->attr_voltage_ext_vcs_bias_up) - (BIAS_PCT_UNIT * (double) + attr->attr_voltage_ext_vcs_bias_down); + *volt_int_vdd_bias = 1.0 + (BIAS_PCT_UNIT * (double) + attr->attr_voltage_int_vdd_bias_up) - (BIAS_PCT_UNIT * (double) + attr->attr_voltage_int_vdd_bias_down); + *volt_int_vcs_bias = 1.0 + (BIAS_PCT_UNIT * (double) + attr->attr_voltage_int_vcs_bias_up) - (BIAS_PCT_UNIT * (double) + attr->attr_voltage_int_vcs_bias_down); + + // loop over each operating point + for (i=0; i <= 4; i++) + { + attr_mvpd_data[i][0] = (uint32_t) ((( (double)attr_mvpd_data[i][0]) * freq_bias) + + 0.5); + attr_mvpd_data[i][1] = (uint32_t) ((( (double)attr_mvpd_data[i][1]) * + volt_ext_vdd_bias) + 0.5); + attr_mvpd_data[i][3] = (uint32_t) ((( (double)attr_mvpd_data[i][3]) * + volt_ext_vcs_bias) + 0.5); + } + + FAPI_INF("BIAS freq = %f", freq_bias); + FAPI_INF("BIAS vdd ext = %f vcs ext = %f", volt_ext_vdd_bias, + volt_ext_vcs_bias); + FAPI_INF("BIAS vdd int = %f vcs int = %f", *volt_int_vdd_bias, + *volt_int_vcs_bias); + + return l_rc; + } // end proc_get_extint_bias /// ------------------------------------------------------------ @@ -1035,78 +1673,117 @@ ReturnCode proc_get_extint_bias(uint32_t attr_mvpd_data[PV_D][PV_W], /// \param[in] *attr => pointer to attribute list structure /// ------------------------------------------------------------ -ReturnCode proc_upd_cpmrange (PstateSuperStructure *pss, - const AttributeList *attr) -{ - ReturnCode l_rc; - int rc = 0; - uint8_t i = 0; - uint8_t valid_points = 0; - Pstate pstate; - uint32_t freq_khz; - - do - { - // extract valid points from attribute and put into superstructure - valid_points = attr->attr_cpm_inflection_points[8]; - pss->cpmranges.validRanges = valid_points; - - FAPI_INF("CPM valid points = %u", valid_points); - - // loop over valid points in attribute and convert to Khz and then convert to pstate value - for (i = 0; i < valid_points; i++) { - freq_khz = attr->attr_cpm_inflection_points[i] * revle32(pss->gpst.frequency_step_khz); - FAPI_INF("Converting CPM inflection point %u (%u khz) to Pstate", i, freq_khz); - rc = freq2pState(&(pss->gpst), freq_khz, &pstate); if (rc) break; - rc = pstate_minmax_chk(&(pss->gpst), &pstate); if (rc) break; - pss->cpmranges.inflectionPoint[i] = pstate; - - FAPI_INF("CPM point freq_khz = %u pstate = %d",freq_khz, pstate); - } + ReturnCode proc_upd_cpmrange (PstateSuperStructure *pss, + const AttributeList *attr) + { + ReturnCode l_rc; + int rc = 0; + uint8_t i = 0; + uint8_t valid_points = 0; + Pstate pstate; + uint32_t freq_khz; + + do + { + // extract valid points from attribute and put into superstructure + valid_points = attr->attr_cpm_inflection_points[8]; + pss->cpmranges.validRanges = valid_points; + + FAPI_INF("CPM valid points = %u", valid_points); + + // loop over valid points in attribute and convert to Khz and then convert to pstate value + for (i = 0; i < valid_points; i++) + { + freq_khz = attr->attr_cpm_inflection_points[i] * revle32( + pss->gpst.frequency_step_khz); + FAPI_INF("Converting CPM inflection point %u (%u khz) to Pstate", i, freq_khz); + rc = freq2pState(&(pss->gpst), freq_khz, &pstate); + + if (rc) + { + break; + } + + rc = pstate_minmax_chk(&(pss->gpst), &pstate); + + if (rc) + { + break; + } + + pss->cpmranges.inflectionPoint[i] = pstate; + + FAPI_INF("CPM point freq_khz = %u pstate = %d",freq_khz, pstate); + } - if (rc) break; + if (rc) + { + break; + } - // convert pMax attribute to Khz and then convert to pstate value + // convert pMax attribute to Khz and then convert to pstate value - if (attr->attr_cpm_inflection_points[9] == 0) { - FAPI_INF(" CPM pMax = 0. Skipping conversion to pstate"); - } - else { - freq_khz = attr->attr_cpm_inflection_points[9] * revle32(pss->gpst.frequency_step_khz); - FAPI_INF("Converting CPM pMax (%u khz) to Pstate", freq_khz); - rc = freq2pState(&(pss->gpst), freq_khz, &pstate); if (rc) break; - rc = pstate_minmax_chk(&(pss->gpst), &pstate); if (rc) break; - pss->cpmranges.pMax = pstate; - - FAPI_INF("CPM pMax freq_khz = %u pstate = %d",freq_khz, pstate); - } + if (attr->attr_cpm_inflection_points[9] == 0) + { + FAPI_INF(" CPM pMax = 0. Skipping conversion to pstate"); + } + else + { + freq_khz = attr->attr_cpm_inflection_points[9] * revle32( + pss->gpst.frequency_step_khz); + FAPI_INF("Converting CPM pMax (%u khz) to Pstate", freq_khz); + rc = freq2pState(&(pss->gpst), freq_khz, &pstate); - } while (0); + if (rc) + { + break; + } - // ------------------------------------------------------ - // check error code from freq2pState or pstate_minmax_chk - // ------------------------------------------------------ - if (rc) { - int & RETURN_CODE = rc; - int8_t & PSTATE = pstate; - uint32_t & FREQ_KHZ = freq_khz; + rc = pstate_minmax_chk(&(pss->gpst), &pstate); - if (rc == -PSTATE_LT_PSTATE_MIN || rc == -PSTATE_GT_PSTATE_MAX) { - FAPI_ERR("**** ERROR : Computed pstate for freq (%d khz) out of bounds of MAX/MIN possible rc = %d", freq_khz, rc); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PSTATE_MINMAX_BOUNDS_ERROR); - } - else if (rc == -GPST_PSTATE_GT_GPST_PMAX){ - FAPI_ERR("**** ERROR : Computed pstate is greater than max pstate in gpst (computed pstate = %d max pstate = %d rc = %d", pstate, gpst_pmax(&(pss->gpst)), rc ); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PSTATE_GT_GPSTPMAX_ERROR); - } - else { - FAPI_ERR("**** ERROR : Bad Return code rc = %d", rc ); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_ERROR); - } - } + if (rc) + { + break; + } + + pss->cpmranges.pMax = pstate; + + FAPI_INF("CPM pMax freq_khz = %u pstate = %d",freq_khz, pstate); + } - return l_rc; -} // end proc_upd_cpmrange + } + while (0); + + // ------------------------------------------------------ + // check error code from freq2pState or pstate_minmax_chk + // ------------------------------------------------------ + if (rc) + { + int & RETURN_CODE = rc; + int8_t & PSTATE = pstate; + uint32_t & FREQ_KHZ = freq_khz; + + if (rc == -PSTATE_LT_PSTATE_MIN || rc == -PSTATE_GT_PSTATE_MAX) + { + FAPI_ERR("**** ERROR : Computed pstate for freq (%d khz) out of bounds of MAX/MIN possible rc = %d", + freq_khz, rc); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PSTATE_MINMAX_BOUNDS_ERROR); + } + else if (rc == -GPST_PSTATE_GT_GPST_PMAX) + { + FAPI_ERR("**** ERROR : Computed pstate is greater than max pstate in gpst (computed pstate = %d max pstate = %d rc = %d", + pstate, gpst_pmax(&(pss->gpst)), rc ); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PSTATE_GT_GPSTPMAX_ERROR); + } + else + { + FAPI_ERR("**** ERROR : Bad Return code rc = %d", rc ); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_ERROR); + } + } + + return l_rc; + } // end proc_upd_cpmrange /// ------------------------------------------------------------------- @@ -1115,97 +1792,111 @@ ReturnCode proc_upd_cpmrange (PstateSuperStructure *pss, /// \param[in] *attr => pointer to attribute list structure /// ------------------------------------------------------------------- -ReturnCode proc_boost_gpst (PstateSuperStructure *pss, - uint32_t attr_boost_percent) -{ - ReturnCode l_rc; - uint8_t i; - uint8_t idx; - double boosted_pct; - uint32_t boosted_freq_khz; - uint32_t pstate0_frequency_khz; - uint32_t frequency_step_khz; - uint32_t pstate_diff; - gpst_entry_t entry; - uint8_t gpsi_max; - - const uint32_t MAXIMUM_BOOST_PERCENT_SUPPORTED = 20; - const uint32_t MAXIMUM_PSTATE_RANGE = 255; // maximum represented by uint8_t - - do - { - - if (attr_boost_percent == 0) { - FAPI_INF("CPM Turbo Boost Attribute = 0 -- no boosting will be done"); - break; - } + ReturnCode proc_boost_gpst (PstateSuperStructure *pss, + uint32_t attr_boost_percent) + { + ReturnCode l_rc; + uint8_t i; + uint8_t idx; + double boosted_pct; + uint32_t boosted_freq_khz; + uint32_t pstate0_frequency_khz; + uint32_t frequency_step_khz; + uint32_t pstate_diff; + gpst_entry_t entry; + uint8_t gpsi_max; + + const uint32_t MAXIMUM_BOOST_PERCENT_SUPPORTED = 20; + const uint32_t MAXIMUM_PSTATE_RANGE = 255; // maximum represented by uint8_t + + do + { + + if (attr_boost_percent == 0) + { + FAPI_INF("CPM Turbo Boost Attribute = 0 -- no boosting will be done"); + break; + } - // check that percentage is rational. Note: attribute information is .1 percent units - if (attr_boost_percent > MAXIMUM_BOOST_PERCENT_SUPPORTED * 10) { - FAPI_ERR("Boost percentage is greater than maximum supported. Max: %u; Value: %u", - MAXIMUM_BOOST_PERCENT_SUPPORTED, attr_boost_percent); - const uint32_t& MAXBOOSTPERCENT = MAXIMUM_BOOST_PERCENT_SUPPORTED; - const uint32_t& ATTRBOOSTPERCENT = attr_boost_percent; - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_INVALID_BOOST_PERCENTAGE_ERROR); - break; - } + // check that percentage is rational. Note: attribute information is .1 percent units + if (attr_boost_percent > MAXIMUM_BOOST_PERCENT_SUPPORTED * 10) + { + FAPI_ERR("Boost percentage is greater than maximum supported. Max: %u; Value: %u", + MAXIMUM_BOOST_PERCENT_SUPPORTED, attr_boost_percent); + const uint32_t& MAXBOOSTPERCENT = MAXIMUM_BOOST_PERCENT_SUPPORTED; + const uint32_t& ATTRBOOSTPERCENT = attr_boost_percent; + FAPI_SET_HWP_ERROR(l_rc, + RC_PROCPM_PSTATE_DATABLOCK_INVALID_BOOST_PERCENTAGE_ERROR); + break; + } - // calculate percent to boost - boosted_pct = 1.0 + (BOOST_PCT_UNIT * (double)attr_boost_percent); + // calculate percent to boost + boosted_pct = 1.0 + (BOOST_PCT_UNIT * (double)attr_boost_percent); - // get turbo frequency (pstate0 frequency) - pstate0_frequency_khz = revle32(pss->gpst.pstate0_frequency_khz); + // get turbo frequency (pstate0 frequency) + pstate0_frequency_khz = revle32(pss->gpst.pstate0_frequency_khz); - // get pstate frequency step - frequency_step_khz = revle32(pss->gpst.frequency_step_khz); + // get pstate frequency step + frequency_step_khz = revle32(pss->gpst.frequency_step_khz); - // calculate boosted frequency - boosted_freq_khz = (uint32_t) ( (double)pstate0_frequency_khz * boosted_pct); + // calculate boosted frequency + boosted_freq_khz = (uint32_t) ( (double)pstate0_frequency_khz * boosted_pct); - // if boosted frequency is <= turbo frequency, then no boost is to be done - if (boosted_freq_khz <= pstate0_frequency_khz) { - FAPI_INF("CPM Turbo Boost Attribute resulted in no increase in pstates - boost_pct = %f turbo_freq_khz = %u boosted_freq_khz = %u", - boosted_pct, pstate0_frequency_khz, boosted_freq_khz); - break; - } - // calculate # pstates that boosted frequency is above turbo - pstate_diff = (boosted_freq_khz/frequency_step_khz) - (pstate0_frequency_khz/frequency_step_khz); - - // pstate difference is 0 then no boost is to be done, else update global pstate table - if (pstate_diff == 0) { - FAPI_INF("CPM Turbo Boost Attribute resulted in no increase in pstates - boost_pct = %f turbo_freq_khz = %u boosted_freq_khz = %u", - boosted_pct, pstate0_frequency_khz, boosted_freq_khz); - break; - } - else if (pstate_diff > MAXIMUM_PSTATE_RANGE) { - FAPI_ERR("Percentage boost calculation overrun produced invalid Pstate Difference: %u", pstate_diff); - const uint32_t& PSTATEDIFF = pstate_diff; - const uint32_t& BOOSTEDFREQKHZ = boosted_freq_khz; - const uint32_t& PSTATE0FREQKHZ = pstate0_frequency_khz; - const uint32_t& FREQSTEPKHZ = frequency_step_khz; - const uint32_t& ATTRBOOSTPERCENT = attr_boost_percent; - const double& BOOSTEDPCT = boosted_pct; - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PSTATE_DIFF_ERROR); - break; - } - else { - gpsi_max = pss->gpst.entries - 1; - entry.value = revle64(pss->gpst.pstate[gpsi_max].value); + // if boosted frequency is <= turbo frequency, then no boost is to be done + if (boosted_freq_khz <= pstate0_frequency_khz) + { + FAPI_INF("CPM Turbo Boost Attribute resulted in no increase in pstates - boost_pct = %f turbo_freq_khz = %u boosted_freq_khz = %u", + boosted_pct, pstate0_frequency_khz, boosted_freq_khz); + break; + } - FAPI_INF("Boosting Pstate Table : percent = %f num pstates added = %d", boosted_pct, pstate_diff); + // calculate # pstates that boosted frequency is above turbo + pstate_diff = (boosted_freq_khz/frequency_step_khz) - + (pstate0_frequency_khz/frequency_step_khz); - for (i = 1; i <= pstate_diff; i++) { - idx = gpsi_max + i; - pss->gpst.pstate[idx].value = revle64(entry.value); - } + // pstate difference is 0 then no boost is to be done, else update global pstate table + if (pstate_diff == 0) + { + FAPI_INF("CPM Turbo Boost Attribute resulted in no increase in pstates - boost_pct = %f turbo_freq_khz = %u boosted_freq_khz = %u", + boosted_pct, pstate0_frequency_khz, boosted_freq_khz); + break; + } + else if (pstate_diff > MAXIMUM_PSTATE_RANGE) + { + FAPI_ERR("Percentage boost calculation overrun produced invalid Pstate Difference: %u", + pstate_diff); + const uint32_t& PSTATEDIFF = pstate_diff; + const uint32_t& BOOSTEDFREQKHZ = boosted_freq_khz; + const uint32_t& PSTATE0FREQKHZ = pstate0_frequency_khz; + const uint32_t& FREQSTEPKHZ = frequency_step_khz; + const uint32_t& ATTRBOOSTPERCENT = attr_boost_percent; + const double& BOOSTEDPCT = boosted_pct; + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PSTATE_DIFF_ERROR); + break; + } + else + { + gpsi_max = pss->gpst.entries - 1; + entry.value = revle64(pss->gpst.pstate[gpsi_max].value); - pss->gpst.entries += pstate_diff; + FAPI_INF("Boosting Pstate Table : percent = %f num pstates added = %d", + boosted_pct, pstate_diff); - } + for (i = 1; i <= pstate_diff; i++) + { + idx = gpsi_max + i; + pss->gpst.pstate[idx].value = revle64(entry.value); + } - } while(0); - return l_rc; -} // end proc_boost_gpst + pss->gpst.entries += pstate_diff; + + } + + } + while(0); + + return l_rc; + } // end proc_boost_gpst /// ------------------------------------------------------------------- @@ -1213,76 +1904,141 @@ ReturnCode proc_boost_gpst (PstateSuperStructure *pss, /// \param[in] poundv_data => pointer to array of #V data /// ------------------------------------------------------------------- -ReturnCode proc_chk_valid_poundv(const Target& i_target, - const uint32_t poundv_data[PV_D][PV_W], - uint8_t chiplet_num, - uint8_t bucket_id) -{ - ReturnCode l_rc; - const uint8_t pv_op_order[S132A_POINTS] = PV_OP_ORDER; - const char *pv_op_str[S132A_POINTS] = PV_OP_ORDER_STR; - uint8_t i = 0; - - do - { - // check for non-zero freq, voltage, or current in valid operating points - for (i = 0; i <= S132A_POINTS-1; i++) { - - FAPI_INF("Checking for Zero valued data in each #V operating point (%s) f=%u v=%u i=%u v=%u i=%u", - pv_op_str[pv_op_order[i]], - poundv_data[pv_op_order[i]][0], - poundv_data[pv_op_order[i]][1], - poundv_data[pv_op_order[i]][2], - poundv_data[pv_op_order[i]][3], - poundv_data[pv_op_order[i]][4]); - - if (poundv_data[pv_op_order[i]][0] == 0 || - poundv_data[pv_op_order[i]][1] == 0 || - poundv_data[pv_op_order[i]][2] == 0 || - poundv_data[pv_op_order[i]][3] == 0 || - poundv_data[pv_op_order[i]][4] == 0 ) { - - FAPI_ERR("**** ERROR : Zero valued data found in #V (chiplet = %u bucket id = %u op point = %s)", chiplet_num, bucket_id, pv_op_str[pv_op_order[i]]); - const uint8_t& OP_POINT = pv_op_order[i]; - const uint8_t& CHIPLET_NUM = chiplet_num; - const uint8_t& BUCKET_ID = bucket_id; - const Target &CHIP_TARGET = i_target; - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PDV_ZERO_DATA_ERROR); - break; - } - } + ReturnCode proc_chk_valid_poundv(const Target& i_target, + AttributeList* i_attr, + const uint32_t poundv_data[PV_D][PV_W], + uint32_t* valid_pdv_points, + uint8_t chiplet_num, + uint8_t bucket_id) + + { + ReturnCode l_rc; + const uint8_t pv_op_order[S132A_POINTS] = PV_OP_ORDER; + const char *pv_op_str[S132A_POINTS] = PV_OP_ORDER_STR; + uint8_t i = 0; + bool suspend_ut_check = false; + + do + { + // check for non-zero freq, voltage, or current in valid operating points + for (i = 0; i <= S132A_POINTS-1; i++) + { + FAPI_INF("Checking for Zero valued data in each #V operating point (%s) f=%u v=%u i=%u v=%u i=%u", + pv_op_str[pv_op_order[i]], + poundv_data[pv_op_order[i]][0], + poundv_data[pv_op_order[i]][1], + poundv_data[pv_op_order[i]][2], + poundv_data[pv_op_order[i]][3], + poundv_data[pv_op_order[i]][4]); + + if (i_attr->attr_wof_enabled && (strcmp(pv_op_str[pv_op_order[i]], "UltraTurbo") == 0)) + { + + if (poundv_data[pv_op_order[i]][0] == 0 || + poundv_data[pv_op_order[i]][1] == 0 || + poundv_data[pv_op_order[i]][2] == 0 || + poundv_data[pv_op_order[i]][3] == 0 || + poundv_data[pv_op_order[i]][4] == 0 ) + { + + FAPI_INF("**** WARNING: WOF is enabled but zero valued data found in #V (chiplet = %u bucket id = %u op point = %s)", + chiplet_num, bucket_id, pv_op_str[pv_op_order[i]]); + FAPI_INF("**** WARNING: Disabling WOF and continuing"); + const uint8_t& OP_POINT = pv_op_order[i]; + const uint8_t& CHIPLET_NUM = chiplet_num; + const uint8_t& BUCKET_ID = bucket_id; + const Target &CHIP_TARGET = i_target; + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PDV_ZERO_DATA_UT_ERROR); + suspend_ut_check = true; + } + } + else if ((!i_attr->attr_wof_enabled) && (strcmp(pv_op_str[pv_op_order[i]], "UltraTurbo") == 0)) + { + FAPI_INF("**** NOTE: WOF is disabled so the UltraTurbo VPD is not being checked"); + suspend_ut_check = true; + } + else + { + + if (poundv_data[pv_op_order[i]][0] == 0 || + poundv_data[pv_op_order[i]][1] == 0 || + poundv_data[pv_op_order[i]][2] == 0 || + poundv_data[pv_op_order[i]][3] == 0 || + poundv_data[pv_op_order[i]][4] == 0 ) + { + + FAPI_ERR("**** ERROR : Zero valued data found in #V (chiplet = %u bucket id = %u op point = %s)", + chiplet_num, bucket_id, pv_op_str[pv_op_order[i]]); + const uint8_t& OP_POINT = pv_op_order[i]; + const uint8_t& CHIPLET_NUM = chiplet_num; + const uint8_t& BUCKET_ID = bucket_id; + const Target &CHIP_TARGET = i_target; + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PDV_ZERO_DATA_ERROR); + break; + } + } + } - if (l_rc) break; - - // check valid operating points' values have this relationship (power save <= nominal <= turbo) - for (i = 1; i <= S132A_POINTS-1; i++) { - - FAPI_INF("Checking for relationship between #V operating point (%s <= %s)", pv_op_str[pv_op_order[i-1]], pv_op_str[pv_op_order[i]]); - FAPI_INF(" f=%u <= f=%u", poundv_data[pv_op_order[i-1]][0], poundv_data[pv_op_order[i]][0]); - FAPI_INF(" v=%u <= v=%u i=%u <= i=%u", poundv_data[pv_op_order[i-1]][1], poundv_data[pv_op_order[i]][1], poundv_data[pv_op_order[i-1]][2], poundv_data[pv_op_order[i]][2]); - FAPI_INF(" v=%u <= v=%u i=%u <= i=%u", poundv_data[pv_op_order[i-1]][3], poundv_data[pv_op_order[i]][3], poundv_data[pv_op_order[i-1]][4], poundv_data[pv_op_order[i]][4]); - - if (poundv_data[pv_op_order[i-1]][0] > poundv_data[pv_op_order[i]][0] || - poundv_data[pv_op_order[i-1]][1] > poundv_data[pv_op_order[i]][1] || - poundv_data[pv_op_order[i-1]][2] > poundv_data[pv_op_order[i]][2] || - poundv_data[pv_op_order[i-1]][3] > poundv_data[pv_op_order[i]][3] || - poundv_data[pv_op_order[i-1]][4] > poundv_data[pv_op_order[i]][4] ) { - - FAPI_ERR("**** ERROR : Relationship error between #V operating point (%s <= %s)(power save <= nominal <= turbo) (chiplet = %u bucket id = %u op point = %u)", - pv_op_str[pv_op_order[i-1]], pv_op_str[pv_op_order[i]], chiplet_num, bucket_id, pv_op_order[i]); - const uint8_t& OP_POINT = pv_op_order[i]; - const uint8_t& CHIPLET_NUM = chiplet_num; - const uint8_t& BUCKET_ID = bucket_id; - const Target &CHIP_TARGET = i_target; - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PDV_OPPOINT_ORDER_ERROR); - break; - } - } + if (l_rc) + { + // If an error was found where suspension was flagged, keep going. + // If not, break to exit point. + if (!suspend_ut_check) + break; + } + + + // Adjust the valid operating point based on UltraTurbo presence + // and WOF enablement + *valid_pdv_points = S132A_POINTS; + + if (suspend_ut_check) + (*valid_pdv_points)--; + + FAPI_DBG("valid_pdv_points = %d", *valid_pdv_points); + + // check valid operating points' values have this relationship (power save <= nominal <= turbo <= ultraturbo) + for (i = 1; i <= (*valid_pdv_points)-1; i++) + { + + FAPI_INF("Checking for relationship between #V operating point (%s <= %s)", + pv_op_str[pv_op_order[i-1]], pv_op_str[pv_op_order[i]]); + FAPI_INF(" f=%u <= f=%u", poundv_data[pv_op_order[i-1]][0], + poundv_data[pv_op_order[i]][0]); + FAPI_INF(" v=%u <= v=%u i=%u <= i=%u", poundv_data[pv_op_order[i-1]][1], + poundv_data[pv_op_order[i]][1], poundv_data[pv_op_order[i-1]][2], + poundv_data[pv_op_order[i]][2]); + FAPI_INF(" v=%u <= v=%u i=%u <= i=%u", poundv_data[pv_op_order[i-1]][3], + poundv_data[pv_op_order[i]][3], poundv_data[pv_op_order[i-1]][4], + poundv_data[pv_op_order[i]][4]); + + if (i_attr->attr_wof_enabled && strcmp(pv_op_str[pv_op_order[i]], "UltraTurbo") && !suspend_ut_check ) + { + if (poundv_data[pv_op_order[i-1]][0] > poundv_data[pv_op_order[i]][0] || + poundv_data[pv_op_order[i-1]][1] > poundv_data[pv_op_order[i]][1] || + poundv_data[pv_op_order[i-1]][2] > poundv_data[pv_op_order[i]][2] || + poundv_data[pv_op_order[i-1]][3] > poundv_data[pv_op_order[i]][3] || + poundv_data[pv_op_order[i-1]][4] > poundv_data[pv_op_order[i]][4] ) + { + + FAPI_ERR("**** ERROR : Relationship error between #V operating point (%s <= %s)(power save <= nominal <= turbo <= ultraturbo) (chiplet = %u bucket id = %u op point = %u)", + pv_op_str[pv_op_order[i-1]], pv_op_str[pv_op_order[i]], chiplet_num, bucket_id, + pv_op_order[i]); + const uint8_t& OP_POINT = pv_op_order[i]; + const uint8_t& CHIPLET_NUM = chiplet_num; + const uint8_t& BUCKET_ID = bucket_id; + const Target &CHIP_TARGET = i_target; + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PDV_OPPOINT_ORDER_ERROR); + break; + } + } + } - } while(0); + } + while(0); - return l_rc; -} + return l_rc; + } /// ------------------------------------------------------------------- @@ -1290,20 +2046,20 @@ ReturnCode proc_chk_valid_poundv(const Target& i_target, /// \param[inout] *pss => pointer to pstate superstructure /// \param[in] *attr => pointer to attribute list structure /// ------------------------------------------------------------------- -ReturnCode proc_res_clock (PstateSuperStructure *pss, - AttributeList *attr_list) -{ - ReturnCode l_rc; - int rc = 0; - uint32_t freq_khz = 0; - Pstate pstate = 0; - - do - { - // ---------------------------------------------------------------------------- - // convert resonant clock frequencies to pstate value and set in superstructure - // ---------------------------------------------------------------------------- - #define DATABLOCK_RESCLK(attr_name, ps_name) \ + ReturnCode proc_res_clock (PstateSuperStructure *pss, + AttributeList *attr_list) + { + ReturnCode l_rc; + int rc = 0; + uint32_t freq_khz = 0; + Pstate pstate = 0; + + do + { + // ---------------------------------------------------------------------------- + // convert resonant clock frequencies to pstate value and set in superstructure + // ---------------------------------------------------------------------------- +#define DATABLOCK_RESCLK(attr_name, ps_name) \ freq_khz = attr_list->attr_name; \ FAPI_INF("Converting %s (%u khz) to Pstate", #attr_name, freq_khz); \ rc = freq2pState(&(pss->gpst), freq_khz, &pstate); \ @@ -1315,34 +2071,45 @@ ReturnCode proc_res_clock (PstateSuperStructure *pss, } \ pss->resclk.ps_name = pstate; - DATABLOCK_RESCLK(attr_pm_resonant_clock_full_clock_sector_buffer_frequency, full_csb_ps); - DATABLOCK_RESCLK(attr_pm_resonant_clock_low_band_lower_frequency, res_low_lower_ps); - DATABLOCK_RESCLK(attr_pm_resonant_clock_low_band_upper_frequency, res_low_upper_ps); - DATABLOCK_RESCLK(attr_pm_resonant_clock_high_band_lower_frequency, res_high_lower_ps); - DATABLOCK_RESCLK(attr_pm_resonant_clock_high_band_upper_frequency, res_high_upper_ps); - - } while(0); - - // --------------------------------- - // check error code from freq2pState - // --------------------------------- - if (rc && rc != -GPST_PSTATE_GT_GPST_PMAX) { - int & RETURN_CODE = rc; - int8_t & PSTATE = pstate; - uint32_t & FREQ_KHZ = freq_khz; - - if (rc == -PSTATE_LT_PSTATE_MIN || rc == -PSTATE_GT_PSTATE_MAX) { - FAPI_ERR("**** ERROR : Computed pstate for freq (%d khz) out of bounds of MAX/MIN possible rc = %d", freq_khz, rc); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_FREQ2PSTATE_PSTATE_MINMAX_BOUNDS_ERROR); - } - else { - FAPI_ERR("**** ERROR : Bad Return code rc = %d", rc ); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_FREQ2PSTATE_ERROR); - } - } + DATABLOCK_RESCLK(attr_pm_resonant_clock_full_clock_sector_buffer_frequency, + full_csb_ps); + DATABLOCK_RESCLK(attr_pm_resonant_clock_low_band_lower_frequency, + res_low_lower_ps); + DATABLOCK_RESCLK(attr_pm_resonant_clock_low_band_upper_frequency, + res_low_upper_ps); + DATABLOCK_RESCLK(attr_pm_resonant_clock_high_band_lower_frequency, + res_high_lower_ps); + DATABLOCK_RESCLK(attr_pm_resonant_clock_high_band_upper_frequency, + res_high_upper_ps); - return l_rc; -} + } + while(0); + + // --------------------------------- + // check error code from freq2pState + // --------------------------------- + if (rc && rc != -GPST_PSTATE_GT_GPST_PMAX) + { + int & RETURN_CODE = rc; + int8_t & PSTATE = pstate; + uint32_t & FREQ_KHZ = freq_khz; + + if (rc == -PSTATE_LT_PSTATE_MIN || rc == -PSTATE_GT_PSTATE_MAX) + { + FAPI_ERR("**** ERROR : Computed pstate for freq (%d khz) out of bounds of MAX/MIN possible rc = %d", + freq_khz, rc); + FAPI_SET_HWP_ERROR(l_rc, + RC_PROCPM_PSTATE_DATABLOCK_FREQ2PSTATE_PSTATE_MINMAX_BOUNDS_ERROR); + } + else + { + FAPI_ERR("**** ERROR : Bad Return code rc = %d", rc ); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_FREQ2PSTATE_ERROR); + } + } + + return l_rc; + } /// ------------------------------------------------------------ @@ -1351,53 +2118,71 @@ ReturnCode proc_res_clock (PstateSuperStructure *pss, /// \param[in] *attr => pointer to attribute list structure /// ------------------------------------------------------------ -ReturnCode proc_upd_psafe_ps (PstateSuperStructure *pss, - const AttributeList *attr) -{ - ReturnCode l_rc; - int rc = 0; - Pstate pstate; - uint32_t freq_khz; - - do - { - - freq_khz = attr->attr_pm_safe_frequency*1000; - FAPI_INF("Converting attr_pm_safe_frequency in %u khz to Pstate", freq_khz); - rc = freq2pState(&(pss->gpst), freq_khz, &pstate); - if(rc) break; - FAPI_INF("Producing pstate = %d for attr_pm_safe_frequency = %u khz", pstate, freq_khz); - rc = pstate_minmax_chk(&(pss->gpst), &pstate); - if(rc) break; - FAPI_IMP("Now set psafe in Global Pstate Table to be pstate of attr_pm_safe_frequency"); - pss->gpst.psafe = pstate; - - } while (0); - - // ------------------------------------------------------ - // check error code from freq2pState or pstate_minmax_chk - // ------------------------------------------------------ - if (rc) { - int & RETURN_CODE = rc; - int8_t & PSTATE = pstate; - uint32_t & FREQ_KHZ = freq_khz; - - if (rc == -PSTATE_LT_PSTATE_MIN || rc == -PSTATE_GT_PSTATE_MAX) { - FAPI_ERR("**** ERROR : Computed pstate for freq (%d khz) out of bounds of MAX/MIN possible rc = %d", freq_khz, rc); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PSAFE_MINMAX_BOUNDS_ERROR); - } - else if (rc == -GPST_PSTATE_GT_GPST_PMAX){ - FAPI_ERR("**** ERROR : Computed pstate is greater than max pstate in gpst (computed pstate = %d max pstate = %d rc = %d", pstate, gpst_pmax(&(pss->gpst)), rc ); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PSAFE_GT_GPSTPMAX_ERROR); - } - else { - FAPI_ERR("**** ERROR : Bad Return code rc = %d", rc ); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PSAFE_ERROR); - } - } + ReturnCode proc_upd_psafe_ps (PstateSuperStructure *pss, + const AttributeList *attr) + { + ReturnCode l_rc; + int rc = 0; + Pstate pstate; + uint32_t freq_khz; + + do + { - return l_rc; -} // end proc_upd_psafe_ps + freq_khz = attr->attr_pm_safe_frequency*1000; + FAPI_INF("Converting attr_pm_safe_frequency in %u khz to Pstate", freq_khz); + rc = freq2pState(&(pss->gpst), freq_khz, &pstate); + + if(rc) + { + break; + } + + FAPI_INF("Producing Pstate = %d for attr_pm_safe_frequency = %u khz", pstate, + freq_khz); + rc = pstate_minmax_chk(&(pss->gpst), &pstate); + + if(rc) + { + break; + } + + FAPI_IMP("Setting Psafe in Global Pstate Table to be Pstate of attr_pm_safe_frequency"); + pss->gpst.psafe = pstate; + + } + while (0); + + // ------------------------------------------------------ + // check error code from freq2pState or pstate_minmax_chk + // ------------------------------------------------------ + if (rc) + { + int & RETURN_CODE = rc; + int8_t & PSTATE = pstate; + uint32_t & FREQ_KHZ = freq_khz; + + if (rc == -PSTATE_LT_PSTATE_MIN || rc == -PSTATE_GT_PSTATE_MAX) + { + FAPI_ERR("**** ERROR : Computed pstate for freq (%d khz) out of bounds of MAX/MIN possible rc = %d", + freq_khz, rc); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PSAFE_MINMAX_BOUNDS_ERROR); + } + else if (rc == -GPST_PSTATE_GT_GPST_PMAX) + { + FAPI_ERR("**** ERROR : Computed pstate is greater than max pstate in gpst (computed pstate = %d max pstate = %d rc = %d", + pstate, gpst_pmax(&(pss->gpst)), rc ); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PSAFE_GT_GPSTPMAX_ERROR); + } + else + { + FAPI_ERR("**** ERROR : Bad Return code rc = %d", rc ); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PSAFE_ERROR); + } + } + + return l_rc; + } // end proc_upd_psafe_ps /// ------------------------------------------------------------ @@ -1406,53 +2191,134 @@ ReturnCode proc_upd_psafe_ps (PstateSuperStructure *pss, /// \param[in] *attr => pointer to attribute list structure /// ------------------------------------------------------------ -ReturnCode proc_upd_floor_ps (PstateSuperStructure *pss, - const AttributeList *attr) -{ - ReturnCode l_rc; - int rc = 0; - Pstate pstate; - uint32_t freq_khz; - - do - { - - freq_khz = attr->attr_freq_core_floor*1000; - FAPI_INF("Converting attr_freq_core_floor in %u khz to Pstate", freq_khz); - rc = freq2pState(&(pss->gpst), freq_khz, &pstate); - if(rc) break; - FAPI_INF("Producing pstate = %d for attr_freq_core_floor = %u khz", pstate, freq_khz); - rc = pstate_minmax_chk(&(pss->gpst), &pstate); - if(rc) break; - FAPI_IMP("Now set pfloor in Global Pstate Table to be pstate of attr_freq_core_floor"); - pss->gpst.pfloor = pstate; - - } while (0); - - // ------------------------------------------------------ - // check error code from freq2pState or pstate_minmax_chk - // ------------------------------------------------------ - if (rc) { - int & RETURN_CODE = rc; - int8_t & PSTATE = pstate; - uint32_t & FREQ_KHZ = freq_khz; - - if (rc == -PSTATE_LT_PSTATE_MIN || rc == -PSTATE_GT_PSTATE_MAX) { - FAPI_ERR("**** ERROR : Computed pstate for freq (%d khz) out of bounds of MAX/MIN possible rc = %d", freq_khz, rc); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PFLOOR_MINMAX_BOUNDS_ERROR); - } - else if (rc == -GPST_PSTATE_GT_GPST_PMAX){ - FAPI_ERR("**** ERROR : Computed pstate is greater than max pstate in gpst (computed pstate = %d max pstate = %d rc = %d", pstate, gpst_pmax(&(pss->gpst)), rc ); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PFLOOR_GT_GPSTPMAX_ERROR); - } - else { - FAPI_ERR("**** ERROR : Bad Return code rc = %d", rc ); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PFLOOR_ERROR); - } - } + ReturnCode proc_upd_floor_ps (PstateSuperStructure *pss, + const AttributeList *attr) + { + ReturnCode l_rc; + int rc = 0; + Pstate pstate; + uint32_t freq_khz; + + do + { + + freq_khz = attr->attr_freq_core_floor*1000; + FAPI_INF("Converting attr_freq_core_floor in %u khz to Pstate", freq_khz); + rc = freq2pState(&(pss->gpst), freq_khz, &pstate); + + if(rc) + { + break; + } + + FAPI_INF("Producing Pstate = %d for attr_freq_core_floor = %u khz", pstate, + freq_khz); + rc = pstate_minmax_chk(&(pss->gpst), &pstate); + + if(rc) + { + break; + } + + FAPI_IMP("Setting Pfloor in Global Pstate Table to be Pstate of attr_freq_core_floor"); + pss->gpst.pfloor = pstate; + + } + while (0); + + // ------------------------------------------------------ + // check error code from freq2pState or pstate_minmax_chk + // ------------------------------------------------------ + if (rc) + { + int & RETURN_CODE = rc; + int8_t & PSTATE = pstate; + uint32_t & FREQ_KHZ = freq_khz; + + if (rc == -PSTATE_LT_PSTATE_MIN || rc == -PSTATE_GT_PSTATE_MAX) + { + FAPI_ERR("**** ERROR : Computed pstate for freq (%d khz) out of bounds of MAX/MIN possible rc = %d", + freq_khz, rc); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PFLOOR_MINMAX_BOUNDS_ERROR); + } + else if (rc == -GPST_PSTATE_GT_GPST_PMAX) + { + FAPI_ERR("**** ERROR : Computed pstate is greater than max pstate in gpst (computed pstate = %d max pstate = %d rc = %d", + pstate, gpst_pmax(&(pss->gpst)), rc ); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PFLOOR_GT_GPSTPMAX_ERROR); + } + else + { + FAPI_ERR("**** ERROR : Bad Return code rc = %d", rc ); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PFLOOR_ERROR); + } + } + + return l_rc; + } // end proc_upd_floor_ps + +/// ------------------------------------------------------------ +/// \brief Populate a subset of the WOFElements structure from Attributes +/// \param[inout] *pss => pointer to pstate superstructure +/// \param[in] *attr => pointer to attribute list structure +/// ------------------------------------------------------------ + + ReturnCode load_wof_attributes (PstateSuperStructure *pss, + const AttributeList *attr) + { + + + // ----------------------------------------------- + // ATTR_WOF_ENABLED setting + // ----------------------------------------------- + pss->wof.wof_enabled = attr->attr_wof_enabled; + + // ----------------------------------------------- + // ATTR_TDP_RDP_CURRENT_FACTOR value + // ----------------------------------------------- + pss->wof.tdp_rdp_factor = attr->attr_tdp_rdp_current_factor; + + // ----------------------------------------------- + // System Power Distribution value + // ----------------------------------------------- + + pss->wof.vdd_sysparm.loadline_uohm = attr->attr_proc_r_loadline_vdd; + pss->wof.vcs_sysparm.loadline_uohm = attr->attr_proc_r_loadline_vcs; + pss->wof.vdd_sysparm.distloss_uohm = attr->attr_proc_r_distloss_vdd; + pss->wof.vcs_sysparm.distloss_uohm = attr->attr_proc_r_distloss_vcs; + pss->wof.vdd_sysparm.distoffset_uv = attr->attr_proc_vrm_voffset_vdd; + pss->wof.vcs_sysparm.distoffset_uv = attr->attr_proc_vrm_voffset_vcs; + + return FAPI_RC_SUCCESS; + + } // end load_wof_attributes + + +/// ------------------------------------------------------------ +/// \brief Copy VPD operating point into destination in assending order +/// \param[in] &src[VPD_PV_POINTS] => reference to source VPD structure (array) +/// \param[out] *dest[VPD_PV_POINTS] => pointer to destination VpdOperatingPoint structure +/// ------------------------------------------------------------ + + ReturnCode load_mvpd_operating_point (const uint32_t src[PV_D][PV_W], + VpdOperatingPoint *dest) + { + + const uint8_t pv_op_order[S132A_POINTS] = PV_OP_ORDER; + + for (uint32_t i = 0; i < S132A_POINTS; i++) + { + dest[i].frequency_mhz = src[pv_op_order[i]][0]; + dest[i].vdd_5mv = src[pv_op_order[i]][1]; + dest[i].idd_500ma = src[pv_op_order[i]][2]; + dest[i].vdd_maxreg_5mv = src[pv_op_order[i]][1] - DEAD_ZONE_5MV; + dest[i].vcs_5mv = src[pv_op_order[i]][3]; + dest[i].ics_500ma = src[pv_op_order[i]][4]; + dest[i].vcs_maxreg_5mv = src[pv_op_order[i]][3] - DEAD_ZONE_5MV; + } - return l_rc; -} // end proc_upd_floor_ps + return FAPI_RC_SUCCESS; + } // end attr2wof } //end extern C diff --git a/src/usr/hwpf/hwp/pstates/pstates/p8_build_pstate_datablock.H b/src/usr/hwpf/hwp/pstates/pstates/p8_build_pstate_datablock.H index d5447810e..512943d7c 100755 --- a/src/usr/hwpf/hwp/pstates/pstates/p8_build_pstate_datablock.H +++ b/src/usr/hwpf/hwp/pstates/pstates/p8_build_pstate_datablock.H @@ -5,7 +5,9 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* COPYRIGHT International Business Machines Corp. 2013,2014 */ +/* Contributors Listed Below - COPYRIGHT 2013,2015 */ +/* [+] International Business Machines Corp. */ +/* */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ /* you may not use this file except in compliance with the License. */ @@ -20,7 +22,7 @@ /* permissions and limitations under the License. */ /* */ /* IBM_PROLOG_END_TAG */ -// $Id: p8_build_pstate_datablock.H,v 1.14 2014/05/27 15:33:49 daviddu Exp $ +// $Id: p8_build_pstate_datablock.H,v 1.15 2015/05/13 03:12:36 stillgs Exp $ #ifndef _P8_BUILD_PSTATE_DATABLOCK_H_ #define _P8_BUILD_PSTATE_DATABLOCK_H_ @@ -38,29 +40,40 @@ extern "C" { /// \param[in] i_target Chip Target /// \param[in/out] *io_pss Reference to PstateSuperStructure -fapi::ReturnCode p8_build_pstate_datablock(const fapi::Target& i_target, PstateSuperStructure *io_pss); +fapi::ReturnCode +p8_build_pstate_datablock(const fapi::Target& i_target, PstateSuperStructure *io_pss); } // extern "C" -#define S132A_POINTS 3 +#define S132A_POINTS 4 #define PSTATE_STEPSIZE 1 #define EVRM_DELAY_NS 100 -#define DEAD_ZONE_5MV 20 +#define DEAD_ZONE_5MV 20 // 100mV #define PDV_BUFFER_SIZE 51 -#define PDM_BUFFER_SIZE 105 +#define PDV_BUFFER_ALLOC 512 + +//#define PDM_BUFFER_SIZE 105 +#define PDM_BUFFER_SIZE 257 // Value is for version 3 @ 256 + 1 for version number +#define PDM_BUFFER_ALLOC 513 // Value is for version 2 @ 512 + 1 for version number #define BIAS_PCT_UNIT 0.005 #define BOOST_PCT_UNIT 0.001 #define POUNDM_POINTS 13 +#define POUNDM_MEASUREMENTS_PER_POINT 4 // #V 2 dimensional array values (5x5) - 5 operating point and 5 values per operating point #define PV_D 5 #define PV_W 5 // order of operating points from slow to fast in #V -// 1=pwrsave 0=nominal 2=turbo -#define PV_OP_ORDER {1, 0, 2} -#define PV_OP_ORDER_STR {"nominal", "powersave", "turbo"} - +// 1=pwrsave 0=nominal 2=turbo. 3=ultraturbo +#define PV_OP_ORDER {1, 0, 2, 3} +#define PV_OP_ORDER_STR {"Nominal", "PowerSave", "Turbo", "UltraTurbo"} +#define PV_OP_ORDER_MIN_VALID {1, 1, 1, 0} + +// IQ Keyword Sizes +#define IQ_BUFFER_SIZE 9 +#define IQ_BUFFER_ALLOC 64 + typedef struct { uint32_t attr_freq_core_max; uint32_t attr_proc_r_loadline_vdd; @@ -106,6 +119,9 @@ typedef struct { uint8_t attr_chip_ec_feature_ivrm_winkle_bug; uint8_t attr_pm_system_ivrms_enabled; uint8_t attr_pm_system_ivrm_vpd_min_level; + + uint8_t attr_wof_enabled; + uint32_t attr_tdp_rdp_current_factor; } AttributeList; diff --git a/src/usr/hwpf/hwp/pstates/pstates/p8_build_pstate_datablock_errors.xml b/src/usr/hwpf/hwp/pstates/pstates/p8_build_pstate_datablock_errors.xml index 92800bfb5..867196d34 100755 --- a/src/usr/hwpf/hwp/pstates/pstates/p8_build_pstate_datablock_errors.xml +++ b/src/usr/hwpf/hwp/pstates/pstates/p8_build_pstate_datablock_errors.xml @@ -5,7 +5,7 @@ <!-- --> <!-- OpenPOWER HostBoot Project --> <!-- --> -<!-- Contributors Listed Below - COPYRIGHT 2013,2014 --> +<!-- Contributors Listed Below - COPYRIGHT 2013,2015 --> <!-- [+] International Business Machines Corp. --> <!-- --> <!-- --> @@ -22,7 +22,7 @@ <!-- permissions and limitations under the License. --> <!-- --> <!-- IBM_PROLOG_END_TAG --> -<!-- $Id: p8_build_pstate_datablock_errors.xml,v 1.13 2014/07/22 21:46:56 daviddu Exp $ --> +<!-- $Id: p8_build_pstate_datablock_errors.xml,v 1.14 2015/05/13 02:56:56 stillgs Exp $ --> <!-- Error definitions for p8_build_pstate_datablock procedure --> <hwpErrors> <!-- *********************************************************************** --> @@ -449,5 +449,109 @@ <priority>HIGH</priority> </callout> </hwpError> - <!-- *********************************************************************** --> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROCPM_PSTATE_DATABLOCK_IQ_BUFFER_SIZE_ERROR</rc> + <description>IQ Buffer returned is wrong size</description> + <ffdc>BUFFER_SIZE</ffdc> + <callout> + <target>CHIP_TARGET</target> + <priority>HIGH</priority> + </callout> + <callout> + <procedure>CODE</procedure> + <priority>LOW</priority> + </callout> + <deconfigure> + <target>CHIP_TARGET</target> + </deconfigure> + </hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROCPM_PSTATE_DATABLOCK_IQ_MVPD_ERROR</rc> + <description>LRPx access for IQ keyword failed</description> + <ffdc>CHIPLET_NUMBER</ffdc> + <callout> + <target>CHIP_TARGET</target> + <priority>HIGH</priority> + </callout> + <callout> + <procedure>CODE</procedure> + <priority>LOW</priority> + </callout> + <deconfigure> + <target>CHIP_TARGET</target> + </deconfigure> + </hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROCPM_PSTATE_DATABLOCK_IQ_INVALID_VDD_ERROR</rc> + <description>IDDQ measurement for VDD was invalid (eg zero)</description> + <ffdc>RAW_VALUE</ffdc> + <ffdc>LRP_NUMBER</ffdc> + <callout> + <target>CHIP_TARGET</target> + <priority>HIGH</priority> + </callout> + <callout> + <procedure>CODE</procedure> + <priority>LOW</priority> + </callout> + <deconfigure> + <target>CHIP_TARGET</target> + </deconfigure> + </hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROCPM_PSTATE_DATABLOCK_IQ_INVALID_VCS_ERROR</rc> + <description>IDDQ measurement for VCS was invalid (eg zero)</description> + <ffdc>RAW_VALUE</ffdc> + <ffdc>LRP_NUMBER</ffdc> + <callout> + <target>CHIP_TARGET</target> + <priority>HIGH</priority> + </callout> + <callout> + <procedure>CODE</procedure> + <priority>LOW</priority> + </callout> + <deconfigure> + <target>CHIP_TARGET</target> + </deconfigure> + </hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROCPM_PSTATE_DATABLOCK_IQ_INVALID_VIO_ERROR</rc> + <description>IDDQ measurement for VIO was invalid (eg zero)</description> + <ffdc>RAW_VALUE</ffdc> + <callout> + <target>CHIP_TARGET</target> + <priority>HIGH</priority> + </callout> + <callout> + <procedure>CODE</procedure> + <priority>LOW</priority> + </callout> + <deconfigure> + <target>CHIP_TARGET</target> + </deconfigure> + </hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROCPM_PSTATE_DATABLOCK_PDV_ZERO_DATA_UT_ERROR</rc> + <description>Zero valued data found in #V for UltraTubro point. Continuing + Pstate generation</description> + <ffdc>OP_POINT</ffdc> + <ffdc>CHIPLET_NUM</ffdc> + <ffdc>BUCKET_ID</ffdc> + <callout> + <target>CHIP_TARGET</target> + <priority>HIGH</priority> + </callout> + <callout> + <procedure>CODE</procedure> + <priority>LOW</priority> + </callout> + </hwpError> + <!-- *********************************************************************** --> </hwpErrors> diff --git a/src/usr/hwpf/hwp/pstates/pstates/pstate_tables.c b/src/usr/hwpf/hwp/pstates/pstates/pstate_tables.c index 2a57af50a..5518b3954 100755 --- a/src/usr/hwpf/hwp/pstates/pstates/pstate_tables.c +++ b/src/usr/hwpf/hwp/pstates/pstates/pstate_tables.c @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2013,2014 */ +/* Contributors Listed Below - COPYRIGHT 2013,2015 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -22,7 +22,7 @@ /* permissions and limitations under the License. */ /* */ /* IBM_PROLOG_END_TAG */ -// $Id: pstate_tables.c,v 1.22 2014/07/03 02:57:52 daviddu Exp $ +// $Id: pstate_tables.c,v 1.26 2015/08/20 17:04:06 stillgs Exp $ /// \file pstate_tables.c /// \brief This file contains code used to generate Pstate tables from real or @@ -32,14 +32,53 @@ /// always "given" to OCC either from the FSP (OCC product firmware), or by /// being built-in the image (lab images). + + #include <stdlib.h> #include <stdint.h> #include <stdio.h> #include "lab_pstates.h" #include "pstate_tables.h" -#define MAX(X, Y) \ + +// Debugging support, normally disabled. All of the formatted I/O you see in +// the code is effectively under this switch. + +#ifdef __FAPI + +#include "fapi.H" +#define fprintf(stream, ...) FAPI_ERR(__VA_ARGS__) +#define printf(...) FAPI_INF(__VA_ARGS__) +#define TRACE_NEWLINE "" + +#else // __FAPI + +#include <stdio.h> +#define fprintf(stream, ...) printf("***ERROR*** " __VA_ARGS__) +#define TRACE_NEWLINE "\n" + +#endif // __FAPI + +#define TRACE_ERROR(x) \ + ({ \ + fprintf(stderr, "%s:%d : Returning error code %d " TRACE_NEWLINE, \ + __FILE__, __LINE__, (x)); \ + (x); \ + }) + +#define TRACE_ERRORX(x, ...) \ ({ \ + TRACE_ERROR(x); \ + fprintf(stderr, ##__VA_ARGS__); \ + (x); \ + }) + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX(X, Y) \ + ({ \ typeof (X) __x = (X); \ typeof (Y) __y = (Y); \ (__x > __y) ? __x : __y; \ @@ -122,6 +161,7 @@ revle64(const uint64_t i_x) return rx; } + /// Create a ChipCharacterization from an array of VPD operating points and /// characterization parameters. /// @@ -149,16 +189,17 @@ chip_characterization_create(ChipCharacterization *characterization, VpdOperatingPoint *vpd, OperatingPoint *ops, OperatingPointParameters *parameters, - int points) + uint32_t points) { int rc; - uint8_t i; + uint32_t i, c; uint32_t pstate0_code; - uint8_t gpst_points = 0; // jwy - uint32_t curr_pstate_code = 0; // jwy - uint32_t next_pstate_code = 0; // jwy + uint8_t gpst_points = 0; + uint32_t curr_pstate_code = 0; + uint32_t next_pstate_code = 0; + uint32_t max_cores = 0; + - do { rc = 0; @@ -167,7 +208,8 @@ chip_characterization_create(ChipCharacterization *characterization, break; } if ((vpd == 0) || (points <= 0)) { - rc = -GPST_INVALID_ARGUMENT; + rc = TRACE_ERRORX(-GPST_INVALID_ARGUMENT, + "vpd & points"); break; } @@ -176,6 +218,8 @@ chip_characterization_create(ChipCharacterization *characterization, characterization->parameters = parameters; characterization->points = points; + max_cores = characterization->max_cores; + // Now convert the array of VPD operating point to the array of // internal operating points // @@ -194,19 +238,19 @@ chip_characterization_create(ChipCharacterization *characterization, for (i = 0; i < points; i++) { - // jwy skip vpd point if next point is at same pstate + // Skip vpd point if next point is at same pstate curr_pstate_code = vpd[i].frequency_mhz * 1000 / parameters->frequency_step_khz; - if (i < points - 1) { + if (i < points-1) { next_pstate_code = vpd[i+1].frequency_mhz * 1000 / parameters->frequency_step_khz; } - - if (i < points - 1 && (curr_pstate_code == next_pstate_code)) { + + if (i < points-1 && (curr_pstate_code == next_pstate_code)) { continue; } - + ops[gpst_points].vdd_uv = vpd[i].vdd_5mv * 5000; ops[gpst_points].vcs_uv = vpd[i].vcs_5mv * 5000; - + ops[gpst_points].vdd_maxreg_uv = vpd[i].vdd_maxreg_5mv * 5000; ops[gpst_points].vcs_maxreg_uv = vpd[i].vcs_maxreg_5mv * 5000; @@ -214,17 +258,17 @@ chip_characterization_create(ChipCharacterization *characterization, ops[gpst_points].ics_ma = vpd[i].ics_500ma * 500; ops[gpst_points].frequency_khz = vpd[i].frequency_mhz * 1000; - + // 'Corrected' voltages values add in the load-line & distribution IR drop ops[gpst_points].vdd_corrected_uv = ops[gpst_points].vdd_uv + - ((ops[gpst_points].idd_ma * (parameters->vdd_load_line_uohm + parameters->vdd_distribution_uohm)) / 1000) + // jwy add in distribution_uohm + ((ops[gpst_points].idd_ma * (parameters->vdd_load_line_uohm + parameters->vdd_distribution_uohm)) / 1000) + parameters->vdd_voffset_uv; // SW267784 add in offset in uohm ops[gpst_points].vcs_corrected_uv = ops[gpst_points].vcs_uv + - ((ops[gpst_points].ics_ma * (parameters->vcs_load_line_uohm + parameters->vcs_distribution_uohm)) / 1000) + // jwy add in distribution_uohm + ((ops[gpst_points].ics_ma * (parameters->vcs_load_line_uohm + parameters->vcs_distribution_uohm)) / 1000) + parameters->vcs_voffset_uv; // SW267784 add in offset in uohm // iVRM 'Effective' voltages are set to the measured voltages @@ -236,11 +280,107 @@ chip_characterization_create(ChipCharacterization *characterization, (ops[gpst_points].frequency_khz / parameters->frequency_step_khz) - pstate0_code; + // For WOF, compute the "per active core" point set based on ratioing + // the current at the operating point in a linear fashion. The ratio + // is only computed for up to the number of cores present on this chip + // as the current contained in the VPD is measured with only that number + // of cores active. + if (i == TURBO || i == ULTRA) + { + for (c = 0; c < max_cores; ++c) + { + double ratio = (double)(c+1)/max_cores; + double idd_currentf_ma = (double)ops[gpst_points].idd_ma; + uint32_t idd_current_ratioed_ma = (uint32_t)(idd_currentf_ma * ratio + 0.5); // round up + uint32_t vdd_impedance_uohm = parameters->vdd_load_line_uohm + parameters->vdd_distribution_uohm; + + uint32_t vdd_dist_uplift_uv = + (uint32_t)( idd_current_ratioed_ma * + ((double)vdd_impedance_uohm/1000)); + + ops[gpst_points].vdd_corrected_wof_uv[c] = + ops[gpst_points].vdd_uv + // Base Point with bias but no system effects + vdd_dist_uplift_uv + // Distribution loss based on apportioned current + parameters->vdd_voffset_uv; // Offset present + + printf( "ops[%d].vdd_uv = %u " + "ratio = %f " + "id_ma = %6.0f " + "current ratioed_ma = %d " + "load line = %d " + "dist loss = %d " + "dist impedance uohm %d " + "dist uplift %d uV " + "dist offset %d uV " + "ops[%d].vdd_corrected_wof_uv[%u] = %u" TRACE_NEWLINE, + gpst_points, ops[gpst_points].vdd_uv, + ratio, + idd_currentf_ma, + idd_current_ratioed_ma, + parameters->vdd_load_line_uohm, + parameters->vdd_distribution_uohm, + vdd_impedance_uohm, + vdd_dist_uplift_uv, + parameters->vdd_voffset_uv, + gpst_points, c, ops[gpst_points].vdd_corrected_wof_uv[c]); + + double ics_currentf_ma = (double)ops[gpst_points].ics_ma; + uint32_t ics_current_ratioed_ma = (uint32_t)(ics_currentf_ma * ratio + 0.5); // round up + + uint32_t vcs_impedance_uohm = parameters->vcs_load_line_uohm + parameters->vcs_distribution_uohm; + + uint32_t vcs_dist_uplift_uv = + (uint32_t)( ics_current_ratioed_ma * + ((double)vcs_impedance_uohm/1000)); + + ops[gpst_points].vcs_corrected_wof_uv[c] = + ops[gpst_points].vcs_uv + // Base Point with bias but no system effects + vcs_dist_uplift_uv + // Distribution loss based on apportioned current + parameters->vcs_voffset_uv; // Offset present + + printf( "ops[%d].vcs_uv = %u " + "ratio = %f " + "id_ma = %6.0f " + "current ratioed_ma = %d " + "load line = %d " + "dist loss = %d " + "dist impedance %d " + "dist uplift %d uV " + "dist offset %d UV " + "ops[%d].vcs_corrected_wof_uv[%u] = %u" TRACE_NEWLINE, + gpst_points, ops[gpst_points].vcs_uv, + ratio, + ics_currentf_ma, + ics_current_ratioed_ma, + parameters->vcs_load_line_uohm, + parameters->vcs_distribution_uohm, + ((parameters->vcs_load_line_uohm + + parameters->vcs_distribution_uohm)), + vcs_dist_uplift_uv, + parameters->vcs_voffset_uv, + gpst_points, c, ops[gpst_points].vcs_corrected_wof_uv[c]); + } + } + + printf("gpst_points %u " + "ops[gpst_points].vdd_uv = %u " + "ops[gpst_points].vcs_uv = %u " + "ops[gpst_points].vdd_maxreg_uv = %u " + "ops[gpst_points].vcs_maxreg_uv = %u " + "ops[gpst_points].idd_ma = %u " + "ops[gpst_points].ics_ma = %u" TRACE_NEWLINE, + gpst_points, + ops[gpst_points].vdd_uv, + ops[gpst_points].vcs_uv, + ops[gpst_points].vdd_maxreg_uv, + ops[gpst_points].vcs_maxreg_uv, + ops[gpst_points].idd_ma, + ops[gpst_points].ics_ma); gpst_points++; } - - // jwy set points to adjusted number of points (ie. if vpd point was skipped due to being same pstate - // jwy as next vpd point + + // Set points to adjusted number of points (ie. if vpd point was skipped due to being same pstate + // as next vpd point characterization->points = gpst_points; } while (0); @@ -292,7 +432,8 @@ gpst_stepping_setup(GlobalPstateTable* gpst, (pstate_stepsize > PSTATE_STEPSIZE_MAX) || (vrm_delay_ns < 0) || (vrm_delay_ns > VRM_STEPDELAY_MAX)) { - rc = -GPST_INVALID_ARGUMENT; + rc = TRACE_ERRORX(-GPST_INVALID_ARGUMENT, + "pstate_stepsize"); break; } @@ -306,7 +447,7 @@ gpst_stepping_setup(GlobalPstateTable* gpst, // Normalize the exponential encoding sigbits = 32 - cntlz32(cycles); - + stepdelay_range = (sigbits - VRM_STEPDELAY_RANGE_BITS); if (stepdelay_range < 0) @@ -317,7 +458,8 @@ gpst_stepping_setup(GlobalPstateTable* gpst, stepdelay_value = cycles >> (stepdelay_range + LOG2_VRM_STEPDELAY_DIVIDER); if (stepdelay_range > ((1u << VRM_STEPDELAY_RANGE_BITS) - 1)) { - rc = -GPST_INVALID_ARGUMENT; + rc = TRACE_ERRORX(-GPST_INVALID_ARGUMENT, + "stepdelay_range"); break; } @@ -370,15 +512,15 @@ gpst_entry_create(gpst_entry_t *entry, OperatingPoint *op) if (rc) break; \ gpe.fields.gpe_field = vid; - __SET(vrm11, ROUND_VOLTAGE_UP, evid_vdd, vdd_corrected_uv); - __SET(vrm11, ROUND_VOLTAGE_UP, evid_vcs, vcs_corrected_uv); - __SET(ivid, ROUND_VOLTAGE_DOWN, evid_vdd_eff, vdd_ivrm_effective_uv); - __SET(ivid, ROUND_VOLTAGE_DOWN, evid_vcs_eff, vcs_ivrm_effective_uv); - __SET(ivid, ROUND_VOLTAGE_DOWN, maxreg_vdd, vdd_maxreg_uv); - __SET(ivid, ROUND_VOLTAGE_DOWN, maxreg_vcs, vcs_maxreg_uv); + __SET(vrm11, ROUND_VOLTAGE_UP, evid_vdd, vdd_corrected_uv); + __SET(vrm11, ROUND_VOLTAGE_UP, evid_vcs, vcs_corrected_uv); + __SET(ivid, ROUND_VOLTAGE_DOWN, evid_vdd_eff, vdd_ivrm_effective_uv); + __SET(ivid, ROUND_VOLTAGE_DOWN, evid_vcs_eff, vcs_ivrm_effective_uv); + __SET(ivid, ROUND_VOLTAGE_DOWN, maxreg_vdd, vdd_maxreg_uv); + __SET(ivid, ROUND_VOLTAGE_DOWN, maxreg_vcs, vcs_maxreg_uv); + + ; - ; - // Add the check byte uint8_t gpstCheckByte(uint64_t gpstEntry); @@ -393,6 +535,45 @@ gpst_entry_create(gpst_entry_t *entry, OperatingPoint *op) } +int +vid_mod_entry_create(WOFElements *wof, uint32_t index, uint32_t core, OperatingPoint *op) +{ + int rc = 0; + uint8_t vid; + + do { + + +#define __SETVM(type, round, wof_field, op_field) \ + rc = vuv2##type(op->op_field, round, &vid); \ + if (rc) \ + { \ + fprintf(stderr, " SETVM error: op_field = %u; vid = %u" TRACE_NEWLINE, op->op_field, vid); \ + break; \ + } \ + wof->ut_vid_mod.wof_field = vid; \ + + __SETVM(vrm11, ROUND_VOLTAGE_UP, ut_segment_vdd_vid[index][core], vdd_corrected_wof_uv[core]); + + printf(" op->vdd_corrected_wof_uv[%d] = %u; wof->ut_vid_mod.ut_segment_vdd_vid[%d][%d] = 0x%02X" TRACE_NEWLINE, + core, op->vdd_corrected_wof_uv[core], + index, core, wof->ut_vid_mod.ut_segment_vdd_vid[index][core]); + + __SETVM(vrm11, ROUND_VOLTAGE_UP, ut_segment_vcs_vid[index][core], vcs_corrected_wof_uv[core]); + + + + printf(" op->vcs_corrected_wof_uv[%d] = %u; wof->ut_vid_mod.ut_segment_vcs_vid[%d][%d] = 0x%02X" TRACE_NEWLINE, + core, op->vcs_corrected_wof_uv[core], + index, core, wof->ut_vid_mod.ut_segment_vcs_vid[index][core]); + + } while (0); + + return rc; +} + + + // Linear interpolation of voltages static uint32_t @@ -441,15 +622,19 @@ interpolate(uint32_t base, uint32_t next, int step, int steps) int gpst_create(GlobalPstateTable *gpst, - ChipCharacterization *characterization, + ChipCharacterization *characterization, + WOFElements *wof, int pstate_stepsize, int evrm_delay_ns) { OperatingPoint *ops, interp; - int rc, points; - int32_t entry; + int rc; + uint32_t points, pstates_ut = 0; + int32_t entry, entry_turbo; int32_t pmin, pmax, pstate; - uint8_t fNom, i; + uint8_t fNom; + uint32_t i, c, max_cores; + gpst_entry_t gpst_entry_temp; do { rc = 0; @@ -463,8 +648,9 @@ gpst_create(GlobalPstateTable *gpst, // Check for null or illegal operating point tables - ops = characterization->ops; - points = characterization->points; + ops = characterization->ops; + points = characterization->points; + max_cores = characterization->max_cores; if ((ops == 0) || (points <= 0)) { rc = -GPST_INVALID_OBJECT; @@ -473,6 +659,8 @@ gpst_create(GlobalPstateTable *gpst, pmin = ops[0].pstate; pmax = ops[points - 1].pstate; + printf("**** Check : pmin %x, pmax %x" TRACE_NEWLINE, + pmin, pmax); // Check that the range of Pstates are legal and will actually fit in // the table. 'Fitting' will never be a problem for PgP as long as the @@ -482,18 +670,36 @@ gpst_create(GlobalPstateTable *gpst, if ((pmin < PSTATE_MIN) || (pmax > PSTATE_MAX) || ((pmax - pmin + 1) > GLOBAL_PSTATE_TABLE_ENTRIES)) { - rc = -GPST_INVALID_ARGUMENT; + rc = TRACE_ERRORX(-GPST_INVALID_ARGUMENT, + "pmin %x, PSTATE_MIN %x; pmax %x, PSTATE_MAX %x; pmax - pmin + 1 %x, GLOBAL_PSTATE_TABLE_ENTRIES %x" TRACE_NEWLINE, + pmin, + PSTATE_MIN, + pmax, + PSTATE_MAX, + pmax - pmin + 1, + GLOBAL_PSTATE_TABLE_ENTRIES + ); break; } // Check the ordering constraints for (i = 1; i < points; i++) { - + if ((ops[i].pstate < ops[i - 1].pstate) || - (ops[i].vdd_uv < ops[i - 1].vdd_uv) || // jwy allow them to be equal - (ops[i].vcs_uv < ops[i - 1].vcs_uv)) { // jwy allow them to be equal - rc = -GPST_INVALID_ARGUMENT; + (ops[i].vdd_uv < ops[i - 1].vdd_uv) | // allow them to be equal + (ops[i].vcs_uv < ops[i - 1].vcs_uv)) { // allow them to be equal + rc = TRACE_ERRORX(-GPST_INVALID_ARGUMENT, + "i = %u pstate %x, ops[i - 1].pstate %x; ops[i].vdd_uv %x, ops[i - 1].vdd_uv %x; ops[i].vcs_uv %x, ops[i - 1].vcs_uv %x" TRACE_NEWLINE, + i, + ops[i].pstate, + ops[i - 1].pstate, + ops[i].vdd_uv , + ops[i - 1].vdd_uv, + ops[i].vcs_uv, + ops[i - 1].vcs_uv + ); + break; } } @@ -503,11 +709,11 @@ gpst_create(GlobalPstateTable *gpst, // pstate0_frequency_code (fNom) to the 'nominal' code and set the // DPLL bias to 0. - gpst->pstate0_frequency_khz = + gpst->pstate0_frequency_khz = revle32(characterization->parameters->pstate0_frequency_khz); - gpst->frequency_step_khz = + gpst->frequency_step_khz = revle32(characterization->parameters->frequency_step_khz); - + // Now we can interpolate the operating points to build the // table. Interpolation is done by creating (or using) an // OperatingPoint for each intermediate (or characterized) Pstate. @@ -515,25 +721,23 @@ gpst_create(GlobalPstateTable *gpst, // the operating point. Only the voltages are interpolated, and they // are all interpolated in units of micro-Volts. + // The WOF algorithm augments the interpolation between the Turbo + // and the UltraTurbo points to calculate a differnt segment based + // on the number of cores that might be active. + gpst->pmin = pmin; gpst->entries = pmax - pmin + 1; - + // Set the Pmin Pstate entry = 0; if (gpst_entry_create(&(gpst->pstate[entry]), &(ops[0]))) { - rc = -GPST_INVALID_ENTRY; + rc = TRACE_ERRORX(-GPST_INVALID_ENTRY, + "gpst_entry_create error setting Pmin"); break; } entry++; pstate = pmin; - - // Iterate over characterized operating points... - for (i = 1; i < points; i++) { - - // Interpolate intermediate Pstates... - while (++pstate != ops[i].pstate) { - - interp.pstate = pstate; + printf("**** Check : pstate %x" TRACE_NEWLINE, pstate); #define __INTERPOLATE(field) \ do { \ @@ -543,27 +747,308 @@ gpst_create(GlobalPstateTable *gpst, (ops[i].pstate - ops[i - 1].pstate)); \ } while (0) - __INTERPOLATE(vdd_corrected_uv); - __INTERPOLATE(vcs_corrected_uv); - __INTERPOLATE(vdd_ivrm_effective_uv); - __INTERPOLATE(vcs_ivrm_effective_uv); - __INTERPOLATE(vdd_maxreg_uv); - __INTERPOLATE(vcs_maxreg_uv); - if (gpst_entry_create(&(gpst->pstate[entry]), &interp)) { - rc = - GPST_INVALID_ENTRY; - break; + // Iterate over characterized operating points... + for (i = 1; i < points; i++) { + + // For WOF, handle the Turbo<>UltraTurbo segment differently + if (i == ULTRA) { + + // Save the Turbo Pstate in the GPST structure for future reference + gpst->turbo_ps = ops[i-1].pstate; + + printf( " Turbo -> %d", gpst->turbo_ps); + + for (c = 0; c < max_cores; ++c) { + pstate = gpst->turbo_ps; // Start again + entry = entry_turbo; + pstates_ut = 0; // Turbo is the first pstate + + // -------------------------------------------------- + // Fill in the Turbo information in the WOF structure + interp.pstate = pstate; + + // Compute the VID overlay values for this core count + __INTERPOLATE(vdd_corrected_wof_uv[c]); + __INTERPOLATE(vcs_corrected_wof_uv[c]); + + printf( ">> Turbo UT WOF entry %u pstate %x %-2d index %d " + "ops[%d].vdd_corrected_wof_uv[%d] = %06d " + "ops[%d].vdd_corrected_wof_uv[%d] = %06d " + "interp.vdd_corrected_wof_uv[%d] = %06d ", + entry, + pstate, pstate, + pstates_ut, + i-1, c, ops[i-1].vdd_corrected_wof_uv[c], + i, c, ops[i].vdd_corrected_wof_uv[c], + c, interp.vdd_corrected_wof_uv[c] + ); + + // >>> Note: iVRMs are not supported as active in the Turbo + // to UltraTurbo segment + if (wof->wof_enabled) + { + printf(">>>> WOF Enabled <<<< " TRACE_NEWLINE); + if (vid_mod_entry_create(wof, pstates_ut, c, &interp)) { + rc = TRACE_ERRORX(-GPST_INVALID_ENTRY, + "gpst_entry_create error - vid mod interpolation"); + break; + } + } + + pstates_ut++; + entry++; + + // -------------------------------------------------- + // Interpolate intermediate Pstates... + while (++pstate != ops[i].pstate) { + printf("pstate = %d", pstate); + + interp.pstate = pstate; + + if (wof->wof_enabled) + { + // Compute the VID overlay values for this core count + __INTERPOLATE(vdd_corrected_wof_uv[c]); + __INTERPOLATE(vcs_corrected_wof_uv[c]); + + printf( "UT WOF entry %u pstate %x %-2d index %d " + "ops[%d].vdd_corrected_wof_uv[%d] = %06d " + "ops[%d].vdd_corrected_wof_uv[%d] = %06d " + "interp.vdd_corrected_wof_uv[%d] = %06d ", + entry, + pstate, pstate, + pstates_ut, + i-1, c, ops[i-1].vdd_corrected_wof_uv[c], + i, c, ops[i].vdd_corrected_wof_uv[c], + c, interp.vdd_corrected_wof_uv[c] + ); + + // >>> Note: iVRMs are not supported as active in the Turbo + // to UltraTurbo segment + + if (vid_mod_entry_create(wof, pstates_ut, c, &interp)) { + rc = TRACE_ERRORX(-GPST_INVALID_ENTRY, + "gpst_entry_create error - vid mod interpolation"); + break; + } + + // Increment VID modification table index + pstates_ut++; + } + + // Compute the VIDs for this Pstate + __INTERPOLATE(vdd_corrected_uv); + __INTERPOLATE(vcs_corrected_uv); + __INTERPOLATE(vdd_ivrm_effective_uv); + __INTERPOLATE(vcs_ivrm_effective_uv); + __INTERPOLATE(vdd_maxreg_uv); + __INTERPOLATE(vcs_maxreg_uv); + + // Write the Global Ptate Table if processing the + // maximum core count + if (c == max_cores-1) + { + printf(">>>> Writing GPST entry %d <<<<" TRACE_NEWLINE, entry); + if (gpst_entry_create(&(gpst->pstate[entry]), &interp)) + { + rc = TRACE_ERRORX(-GPST_INVALID_ENTRY, + "gpst_entry_create error - UT interpolation"); + break; + } + + gpst_entry_temp.value = revle64(gpst->pstate[entry].value); + printf("UT entry %u pstate %x %-2d" + "evid_vdd = 0x%02llX (VRM-11) " + "evid_vcs = 0x%02llX (VRM-11) " + "evid_vdd_eff = 0x%02llX (iVID) " + "evid_vcs_eff = 0x%02llX (iVID) " + "maxreg_vdd = 0x%02llX (iVID) " + "maxreg_vcs = 0x%02llX (iVID) ", + entry, + pstate, pstate, + gpst_entry_temp.fields.evid_vdd, + gpst_entry_temp.fields.evid_vcs, + gpst_entry_temp.fields.evid_vdd_eff, + gpst_entry_temp.fields.evid_vcs_eff, + gpst_entry_temp.fields.maxreg_vdd, + gpst_entry_temp.fields.maxreg_vcs); + + } + entry++; + } + if (rc) break; + + // Set the characterized Pstate + if (gpst_entry_create(&(gpst->pstate[entry]), &(ops[i]))) { + rc = TRACE_ERRORX(-GPST_INVALID_ENTRY, + "gpst_entry_create error - normal UT interpolation"); + break; + } + + gpst_entry_temp.value = revle64(gpst->pstate[entry].value); + printf("UT entry %u pstate %x %-2d " + "evid_vdd = 0x%02llX (VRM-11) " + "evid_vcs = 0x%02llX (VRM-11) " + "evid_vdd_eff = 0x%02llX (iVID) " + "evid_vcs_eff = 0x%02llX (iVID) " + "maxreg_vdd = 0x%02llX (iVID) " + "maxreg_vcs = 0x%02llX (iVID) ", + entry, + pstate, pstate, + gpst_entry_temp.fields.evid_vdd, + gpst_entry_temp.fields.evid_vcs, + gpst_entry_temp.fields.evid_vdd_eff, + gpst_entry_temp.fields.evid_vcs_eff, + gpst_entry_temp.fields.maxreg_vdd, + gpst_entry_temp.fields.maxreg_vcs); + + if (wof->wof_enabled) + { + // Fill in the UltraTurbo information in the WOF structure + interp.pstate = pstate; + + // Compute the VID overlay values for this core count + __INTERPOLATE(vdd_corrected_wof_uv[c]); + __INTERPOLATE(vcs_corrected_wof_uv[c]); + + printf( ">> UltraTurbo UT WOF entry %u pstate %x %-2d index %d " + "ops[%d].vdd_corrected_wof_uv[%d] = %06d " + "ops[%d].vdd_corrected_wof_uv[%d] = %06d " + "interp.vdd_corrected_wof_uv[%d] = %06d " TRACE_NEWLINE, + entry, + pstate, pstate, + pstates_ut, + i-1, c, ops[i-1].vdd_corrected_wof_uv[c], + i, c, ops[i].vdd_corrected_wof_uv[c], + c, interp.vdd_corrected_wof_uv[c] + ); + + // >>> Note: iVRMs are not supported as active in the Turbo + // to UltraTurbo segment + + if (vid_mod_entry_create(wof, pstates_ut, c, &interp)) { + rc = TRACE_ERRORX(-GPST_INVALID_ENTRY, + "gpst_entry_create error - vid mod interpolation"); + break; + } + + // Save the UltraTurbo segment Pstate count + wof->ut_vid_mod.ut_segment_pstates = pstates_ut; + + // Save the maximum core count + wof->ut_vid_mod.ut_max_cores = max_cores; + + printf( "UT WOF entry %u pstate %x index %d " + "wof->ut_vid_mod.ut_segment_vcs_vid[%d][%d] = 0x%02X " + "ops[%d].vdd_corrected_uv %d UltraTurbo", + entry, + pstate, + pstates_ut, + pstates_ut, c, wof->ut_vid_mod.ut_segment_vdd_vid[pstates_ut][c], + i, ops[i].vdd_corrected_uv + ); + } + entry++; } - entry++; + } - if (rc) break; + else + { - // Set the characterized Pstate - if (gpst_entry_create(&(gpst->pstate[entry]), &(ops[i]))) { - rc = -GPST_INVALID_ENTRY; - break; + // Save the PowerSave and Nominal Pstate in the GPST structure for future reference + // Get update for each point; + + if (i == NOMINAL) + { + gpst->nominal_ps = ops[i].pstate; + printf( " Nominal Pstate -> %d", gpst->nominal_ps); + + gpst->powersave_ps = ops[i-1].pstate; + printf( " PowerSave Pstate -> %d", gpst->powersave_ps); + } + + // Interpolate intermediate Pstates... + while (++pstate != ops[i].pstate) { + + interp.pstate = pstate; + + __INTERPOLATE(vdd_corrected_uv); + __INTERPOLATE(vcs_corrected_uv); + __INTERPOLATE(vdd_ivrm_effective_uv); + __INTERPOLATE(vcs_ivrm_effective_uv); + __INTERPOLATE(vdd_maxreg_uv); + __INTERPOLATE(vcs_maxreg_uv); + + if (gpst_entry_create(&(gpst->pstate[entry]), &interp)) { + rc = TRACE_ERRORX(-GPST_INVALID_ENTRY, + "gpst_entry_create error - normal interpolation"); + break; + } + + gpst_entry_temp.value = revle64(gpst->pstate[entry].value); + printf( "Non UT entry %u pstate %x %-2d " + "evid_vdd = 0x%02llX (VRM-11) " + "evid_vcs = 0x%02llX (VRM-11) " + "evid_vdd_eff = 0x%02llX (iVID) " + "evid_vcs_eff = 0x%02llX (iVID) " + "maxreg_vdd = 0x%02llX (iVID) " + "maxreg_vcs = 0x%02llX (iVID) ", + entry, + pstate, pstate, + gpst_entry_temp.fields.evid_vdd, + gpst_entry_temp.fields.evid_vcs, + gpst_entry_temp.fields.evid_vdd_eff, + gpst_entry_temp.fields.evid_vcs_eff, + gpst_entry_temp.fields.maxreg_vdd, + gpst_entry_temp.fields.maxreg_vcs); + + entry++; + } + if (rc) break; + + // Set the characterized Pstate + if (gpst_entry_create(&(gpst->pstate[entry]), &(ops[i]))) { + rc = -GPST_INVALID_ENTRY; + break; + } + + gpst_entry_temp.value = revle64(gpst->pstate[entry].value); + printf( ">> VPD Point Non UT entry %u pstate %x %-2d " + "evid_vdd = 0x%02llX (VRM-11) " + "evid_vcs = 0x%02llX (VRM-11) " + "evid_vdd_eff = 0x%02llX (iVID) " + "evid_vcs_eff = 0x%02llX (iVID) " + "maxreg_vdd = 0x%02llX (iVID) " + "maxreg_vcs = 0x%02llX (iVID) ", + entry, + pstate, pstate, + gpst_entry_temp.fields.evid_vdd, + gpst_entry_temp.fields.evid_vcs, + gpst_entry_temp.fields.evid_vdd_eff, + gpst_entry_temp.fields.evid_vcs_eff, + gpst_entry_temp.fields.maxreg_vdd, + gpst_entry_temp.fields.maxreg_vcs); + + // The iVRM maximum pstate is set for each characterization point + // as the points are traversed. The last one processed by this + // clause is Turbo. As iVRMs are not engaged at the Turbo point + // itself, subtract 1. + gpst->ivrm_max_ps = ops[i].pstate - 1; + printf( " ivrm Pstate -> %d Op Point Pstate%d" TRACE_NEWLINE, gpst->ivrm_max_ps, ops[i].pstate); + + // Set the number of entries from Psave to the iVRM maximum + // (Turbo Pstate - 1) + gpst->ivrm_entries = entry - 1; + + // Save the entry for the post Turbo clause. Written for each iteration. + // Only the last one written matters + entry_turbo = entry; + + printf( " entry_turbo -> %d" TRACE_NEWLINE, entry_turbo); + + entry++; } - entry++; } if (rc) break; @@ -578,7 +1063,7 @@ gpst_create(GlobalPstateTable *gpst, gpst->pstate0_frequency_code[i] = revle16(fNom); gpst->dpll_fmax_bias[i] = 0; } - + // Hardcode the vrm delay settings for GA1 // This should be set by gpst_stepping_setup() in the future. gpst->pstate_stepsize = pstate_stepsize; @@ -592,328 +1077,339 @@ gpst_create(GlobalPstateTable *gpst, } -/// Create a local Pstate table +/// Create a local Pstate table /// -/// \param gpst A pointer to a GlobalPstateTable structure for lookup. +/// \param gpst A pointer to a GlobalPstateTable structure for lookup. /// -/// \param lpsa Apointer to a LocalPstateArray structure to populate +/// \param lpsa A pointer to a LocalPstateArray structure to populate /// /// \param dead_zone_5mv dead zone value /// /// \param evrm_delay_ns External VRM delay in nano-seconds /// /// This routine creates a LocalPstateArray by using the dead zone value and -/// data in the GlobalPstateTable +/// data in the GlobalPstateTable. /// /// \retval 0 Success /// /// \retval -LPST_INVALID_OBJECT Either the \a gpst or \a lpsa were NULL (0) or /// obviously invalid or incorrectly initialized. /// -/// \retval -LPST_INVALID_ARGUMENT indicates that the difference between +/// \retval -LPST_INVALID_ARGUMENT indicates that the difference between /// pmax & pmin in gpst is less than deadzone voltage (ie. no data to build lpsa) int -lpst_create(const GlobalPstateTable *gpst, - LocalPstateArray *lpsa, - const uint8_t dead_zone_5mv, - double volt_int_vdd_bias, +lpst_create(const GlobalPstateTable *gpst, + LocalPstateArray *lpsa, + const uint8_t dead_zone_5mv, + double volt_int_vdd_bias, double volt_int_vcs_bias, uint8_t *vid_incr_gt7_nonreg) -{ - int rc = 0; +{ + int rc = 0; int8_t i; uint8_t j; gpst_entry_t entry; - uint32_t turbo_uv; - uint32_t gpst_uv; - uint32_t v_uv; - uint32_t vdd_uv; + uint32_t turbo_uv; + uint32_t gpst_uv; + uint32_t v_uv; + uint32_t vdd_uv; uint8_t v_ivid; uint8_t gpst_ivid; - uint8_t lpst_max_found = 0; - uint32_t lpst_max_uv; - uint8_t lpst_entries; - uint8_t lpst_entries_div4; - uint8_t gpst_index; + uint8_t lpst_max_found = 0; + uint32_t lpst_max_uv; + uint8_t lpst_entries; + uint8_t lpst_entries_div4; + uint8_t gpst_index; Pstate lpst_pmin; Pstate lpst_pstate; - Pstate lpst_max_pstate = 0; - uint8_t vid_incr[3] = {0,0,0}; + Pstate lpst_max_pstate = 0; + uint8_t vid_incr[3] = {0,0,0}; uint8_t steps_above_curr; - uint8_t steps_below_curr; + uint8_t steps_below_curr; uint8_t inc_step; uint8_t dec_step; - + do { - - // Basic pointer checks + + // Basic pointer checks if ((gpst == 0) || (lpsa == 0)) { - rc = -LPST_INVALID_OBJECT; - break; - } + rc = -LPST_INVALID_OBJECT; + break; + } - // ------------------------------------------------------------------ + + // ------------------------------------------------------------------ // find lspt_max in gpst // - lpst_max is gpst entry that is equal to (turbo_vdd - deadzone) // ------------------------------------------------------------------ - entry.value = revle64(gpst->pstate[(gpst->entries)-1].value); - rc = ivid2vuv(entry.fields.evid_vdd_eff, &turbo_uv); if (rc) break; - + + entry.value = revle64(gpst->pstate[(gpst->ivrm_entries)].value); + rc = ivid2vuv(entry.fields.evid_vdd_eff, &turbo_uv); if (rc) break; + + printf("gpst->ivrm_entries = %u, turbo_uv = %u", gpst->ivrm_entries, turbo_uv); + turbo_uv = (uint32_t) (turbo_uv * volt_int_vdd_bias); - lpst_max_uv = turbo_uv - (dead_zone_5mv * 5000); - - for (i = gpst->entries - 1 ; i >= 0; i--) { - entry.value = revle64(gpst->pstate[i].value); + lpst_max_uv = turbo_uv - (dead_zone_5mv * 5000); + + for (i = gpst->ivrm_entries ; i >= 0; i--) { + entry.value = revle64(gpst->pstate[i].value); rc = ivid2vuv(entry.fields.evid_vdd_eff, &v_uv); if (rc) break; - v_uv = (uint32_t) (v_uv * volt_int_vdd_bias); - + v_uv = (uint32_t) (v_uv * volt_int_vdd_bias); + if (lpst_max_uv >= v_uv) { lpst_max_found = 1; lpst_max_pstate = gpst_pmax(gpst) - (gpst->entries - i - 1); + printf("lpst_max_pstate = %x" TRACE_NEWLINE, lpst_max_pstate); break; - } + } } - - if (rc) break; - - // generate a warning if lpst max not found + + if (rc) break; + + // generate a warning if lpst max not found // - indicates that the difference between pmax & pmin in gpst is less than deadzone voltage // - no data will be in lpst (lpst entries = 0) if (lpst_max_found == 0) { rc = -LPST_GPST_WARNING; - break; + break; } - - lpst_entries = gpst->entries; + + lpst_entries = gpst->ivrm_entries; lpst_pmin = gpst->pmin; - + + printf("lpst_entries = %u" TRACE_NEWLINE, lpst_entries); // ---------------------------------------------------------------------------- // now loop over gpst from 0 to lpst_entries and fill in lpst from data in gpst // ---------------------------------------------------------------------------- gpst_index = 0; - lpst_entries_div4 = lpst_entries/4; + lpst_entries_div4 = lpst_entries/4; if ( lpst_entries % 4 != 0) lpst_entries_div4++; - - // current lpst pstate value as table is created + + // current lpst pstate value as table is created lpst_pstate = gpst_pmin(gpst); - + + printf("lpst create before loop: lpst_entries_div4 = %d" TRACE_NEWLINE, lpst_entries_div4); for (i = 0 ; i < lpst_entries_div4; i++) { entry.value = revle64(gpst->pstate[gpst_index].value); - + // compute ivid_vdd rc = ivid2vuv(entry.fields.evid_vdd_eff, &vdd_uv); if (rc) break; vdd_uv = (uint32_t) (vdd_uv * volt_int_vdd_bias); rc = vuv2ivid(vdd_uv, ROUND_VOLTAGE_DOWN, &v_ivid); if (rc) break; lpsa->pstate[i].fields.ivid_vdd = v_ivid; - + // compute ivid_vcs rc = ivid2vuv(entry.fields.evid_vcs_eff, &v_uv); if (rc) break; - v_uv = (uint32_t) (v_uv * volt_int_vcs_bias); + v_uv = (uint32_t) (v_uv * volt_int_vcs_bias); rc = vuv2ivid(v_uv, ROUND_VOLTAGE_DOWN, &v_ivid); if (rc) break; - lpsa->pstate[i].fields.ivid_vcs = v_ivid; - + lpsa->pstate[i].fields.ivid_vcs = v_ivid; + + // -------------------------------------------------------------- + // compute increment for remaining 3 pstates for this lpst entry // -------------------------------------------------------------- - // compute increment for remaining 3 pstates for this lpst entry - // -------------------------------------------------------------- - vid_incr[0] = 0; + vid_incr[0] = 0; vid_incr[1] = 0; vid_incr[2] = 0; - + for (j = 0; j <= 2; j++) { + gpst_index++; - if (gpst_index >= lpst_entries) - break; - + if (gpst_index >= lpst_entries) + break; + entry.value = revle64(gpst->pstate[gpst_index].value); rc = ivid2vuv(entry.fields.evid_vdd_eff, &vdd_uv); if (rc) break; - vdd_uv = (uint32_t) (vdd_uv * volt_int_vdd_bias); + vdd_uv = (uint32_t) (vdd_uv * volt_int_vdd_bias); rc = vuv2ivid(vdd_uv, ROUND_VOLTAGE_DOWN, &v_ivid); if (rc) break; vid_incr[j] = v_ivid - lpsa->pstate[i].fields.ivid_vdd; - + // point to next lpst pstate lpst_pstate++; // the max for this field is 7, so clip to 7 if it's > 7 if (vid_incr[j] > 7) { - vid_incr[j] = 7; - + vid_incr[j] = 7; + // if in regulation, return an error if (lpst_pstate <= lpst_max_pstate) { - rc = -LPST_INCR_CLIP_ERROR ; + rc = TRACE_ERRORX(-LPST_INCR_CLIP_ERROR, + "lpst clip: lpst_pstate %x lpst_max_pstate %x", + lpst_pstate, + lpst_max_pstate + ); break; - } - + } + // if not in regulation, return a warning - if (lpst_pstate > lpst_max_pstate) { + if (lpst_pstate > lpst_max_pstate) { *vid_incr_gt7_nonreg = 1; - } - } - + } + } + } if (rc) break; - - lpsa->pstate[i].fields.ps1_vid_incr = vid_incr[0]; - lpsa->pstate[i].fields.ps2_vid_incr = vid_incr[1]; - lpsa->pstate[i].fields.ps3_vid_incr = vid_incr[2]; - + printf("lpst create after loop" TRACE_NEWLINE); + + lpsa->pstate[i].fields.ps1_vid_incr = vid_incr[0]; + lpsa->pstate[i].fields.ps2_vid_incr = vid_incr[1]; + lpsa->pstate[i].fields.ps3_vid_incr = vid_incr[2]; + // -------------------- // compute power ratios - // -------------------- + // -------------------- float sigma = 3; float iac_wc; float iac; float vout; float pwrratio_f; uint8_t pwrratio; - + // convert to mV and subract 100 mV (note: vdd_uv is the max of the vdd values for this lpst entry) - vout = (float)((vdd_uv/1000) - 100); - + vout = (float)((vdd_uv/1000) - 100); + // equations from Josh iac_wc = 1.25 * ( 28.5 * 1.25 - 16 ) * ( 1 - 0.05 * 2) * 40/71; // testsite equation & ratio of testsite to anticipated produ iac = 1.25 * (-15.78 -0.618 * sigma + 27.6 * vout/1000) * 40/64; // product equation & ratio of testsite to actual product pwrratio_f = iac / iac_wc; - + if (pwrratio_f >= 1.0) pwrratio = 63; - else + else pwrratio = (uint8_t)((pwrratio_f*64) + 0.5); - - lpsa->pstate[i].fields.vdd_core_pwrratio = pwrratio; - lpsa->pstate[i].fields.vcs_core_pwrratio = pwrratio; - lpsa->pstate[i].fields.vdd_eco_pwrratio = pwrratio; - lpsa->pstate[i].fields.vcs_eco_pwrratio = pwrratio; - + + lpsa->pstate[i].fields.vdd_core_pwrratio = pwrratio; + lpsa->pstate[i].fields.vcs_core_pwrratio = pwrratio; + lpsa->pstate[i].fields.vdd_eco_pwrratio = pwrratio; + lpsa->pstate[i].fields.vcs_eco_pwrratio = pwrratio; + // ------------------------------------ // compute increment step and decrement // ------------------------------------ - // - look above current pstate to pstate that is >= 25 mV for inc_step - // - look below current pstate to pstate that is >= 25 mV for dec_step + // - look above current pstate to pstate that is >= 25 mV for inc_step + // - look below current pstate to pstate that is >= 25 mV for dec_step // find # steps above and below current lpst pstate steps_above_curr = gpst_pmax(gpst) - lpst_pstate; steps_below_curr = lpst_pstate - gpst_pmin(gpst); - + // start looking above in gpst to find inc_step inc_step = 0; // default - + for (j = 1; j <= steps_above_curr; j++) { inc_step = j - 1; - entry.value = revle64(gpst->pstate[lpst_pstate - gpst_pmin(gpst) + j].value); + entry.value = revle64(gpst->pstate[lpst_pstate - gpst_pmin(gpst) + j].value); rc = ivid2vuv(entry.fields.evid_vdd_eff, &gpst_uv); if (rc) break; gpst_uv = (uint32_t) (gpst_uv * volt_int_vdd_bias); rc = vuv2ivid(gpst_uv, ROUND_VOLTAGE_DOWN, &gpst_ivid); if (rc) break; - + if ( (gpst_ivid - v_ivid) >= 4) - break; - } - + break; + } if (rc) break; - - // clip inc_step - if (inc_step > 7) + + // clip inc_step + if (inc_step > 7) inc_step = 7; - + lpsa->pstate[i].fields.inc_step = inc_step; // start looking below in gpst to find dec_step dec_step = 0; // default - + for (j = 1; j <= steps_below_curr; j++) { dec_step = j - 1; - entry.value = revle64(gpst->pstate[lpst_pstate - gpst_pmin(gpst) - j].value); + entry.value = revle64(gpst->pstate[lpst_pstate - gpst_pmin(gpst) - j].value); rc = ivid2vuv(entry.fields.evid_vdd_eff, &gpst_uv); if (rc) break; gpst_uv = (uint32_t) (gpst_uv * volt_int_vdd_bias); rc = vuv2ivid(gpst_uv, ROUND_VOLTAGE_DOWN, &gpst_ivid); if (rc) break; - + if ( (v_ivid - gpst_ivid ) >= 4) - break; - } - + break; + } if (rc) break; - - // clip dec_step - if (dec_step > 7) - dec_step = 7; - + + // clip dec_step + if (dec_step > 7) + dec_step = 7; + lpsa->pstate[i].fields.dec_step = dec_step; // Byte reverse the entry into the image. lpsa->pstate[i].value = revle64(lpsa->pstate[i].value); - + gpst_index++; if (gpst_index > lpst_entries) - break; - + break; + // point to next lpst pstate - lpst_pstate++; + lpst_pstate++; } - // set these fields in lpst structure + // set these fields in lpst structure if (lpst_max_found == 0) { lpsa->pmin = 0; lpsa->entries = 0; - } + } else { lpsa->pmin = lpst_pmin; lpsa->entries = lpst_entries; } - - } while (0); - return rc; - -} // end lpst_create + } while (0); + + return rc; -// This routine will fully fill out the VDS region table even if +} // end lpst_create + +// This routine will fully fill out the VDS region table even if // some of the upper entries are not used. void build_vds_region_table( ivrm_parm_data_t* i_ivrm_parms, PstateSuperStructure* pss) -{ +{ uint8_t i; uint32_t vds; uint64_t beg_offset = 0; uint64_t end_offset = 0; - + vds = (i_ivrm_parms->vds_min_range_upper_bound*1000)/IVID_STEP_UV; - end_offset = (uint64_t)vds; - + end_offset = (uint64_t)vds; + for (i = 0; i < i_ivrm_parms->vds_region_entries; i++) { pss->lpsa.vdsvin[i].fields.ivid0 = beg_offset; pss->lpsa.vdsvin[i].fields.ivid1 = end_offset; - + // Calculate offsets for next entry beg_offset = end_offset + 1; - + // clip at 127 if (beg_offset >= 127) beg_offset = 127; - + vds =(uint32_t)( (float)end_offset * (1 + ( (float)i_ivrm_parms->vds_step_percent/100))); end_offset = (uint64_t)vds; - + // clip at 127 if (end_offset >= 127) - end_offset = 127; - } + end_offset = 127; + } } -// This routine will fully fill out the VDS region table even if +// This routine will fully fill out the VDS region table even if // some of the upper entries are not used. void fill_vin_table( ivrm_parm_data_t* i_ivrm_parms, PstateSuperStructure* pss) -{ +{ uint8_t s; uint8_t i; uint32_t idx; - + i = i_ivrm_parms->vin_table_setsperrow; for (i = 0; i < i_ivrm_parms->vds_region_entries; i++) { @@ -929,8 +1425,8 @@ fill_vin_table( ivrm_parm_data_t* i_ivrm_parms, pss->lpsa.vdsvin[idx].fields.pfet7 = i_ivrm_parms->forced_pfetstr_value; // Byte reverse the entry into the image. - pss->lpsa.vdsvin[idx].value = revle64(pss->lpsa.vdsvin[idx].value); - } + pss->lpsa.vdsvin[idx].value = revle64(pss->lpsa.vdsvin[idx].value); + } } } @@ -1039,17 +1535,17 @@ void simeq(int n, double A[], double Y[], double X[]) void fit_file(int n, uint8_t version, double C[], ivrm_cal_data_t* cal_data) { uint8_t i, j, k; - int points; + int points; double y; double Vd, Vs; double x[30]; /* at least 2n */ - double A[2500]; - double Y[50]; + double A[2500]; + double Y[50]; // ----------------------------------------------------------------------------------------- // initialize harcoded values to use for Vs & Vg for version1 // version1 specifies Vd &Vs as uV and 16 bits is not enough to specify values about 65 mV - // ----------------------------------------------------------------------------------------- + // ----------------------------------------------------------------------------------------- double Vs_v1[13]; double Vd_v1[13]; Vd_v1[0] = 700; Vs_v1[0] = 888; @@ -1065,9 +1561,9 @@ void fit_file(int n, uint8_t version, double C[], ivrm_cal_data_t* cal_data) Vd_v1[10] = 981; Vs_v1[10] = 1325; Vd_v1[11] = 881; Vs_v1[11] = 1325; Vd_v1[12] = 731; Vs_v1[12] = 1325; - - points = cal_data->point_valid; - + + points = cal_data->point_valid; + for(i=0; i<n; i++) { for(j=0; j<n; j++) @@ -1076,31 +1572,31 @@ void fit_file(int n, uint8_t version, double C[], ivrm_cal_data_t* cal_data) } Y[i] = 0.0; } - + x[0]=1.0; - + for (k = 0; k <= points-1; k++) { - if (version == 0) { - Vd = Vd_v1[k]; - Vs = Vs_v1[k]; - y = ((double)cal_data->point[k].drain_current)/1000; // uA - } + if (version == 0) { + Vd = Vd_v1[k]; + Vs = Vs_v1[k]; + y = ((double)cal_data->point[k].drain_current)/1000; // uA + } else if (version == 1 || version == 2 || version == 3) { Vd = (double)cal_data->point[k].drain_voltage; // mV Vs = (double)cal_data->point[k].source_voltage; // mV - y = ((double)cal_data->point[k].drain_current)/1000; // uA + y = ((double)cal_data->point[k].drain_current)/1000; // uA } else { //simulation data Vd = (double)cal_data->point[k].drain_voltage; // mV Vs = (double)cal_data->point[k].source_voltage; // mV - y = ((double)cal_data->point[k].drain_current)/1000; // uA + y = ((double)cal_data->point[k].drain_current)/1000; // uA } x[1]=Vs/1.11; // x[1] = target Vin = Vgs / 1.11 x[2]=Vs/1.11-Vd; // x[2] = target Vds = Vin/1.11 - Vout = Vs/1.11 - Vd x[3]=x[1]*x[2]; // x[3] = Vin*Vds - + for(i=0; i<n; i++) { for(j=0; j<n; j++) { A[i*n+j] = A[i*n+j] + x[i]*x[j]; @@ -1108,9 +1604,9 @@ void fit_file(int n, uint8_t version, double C[], ivrm_cal_data_t* cal_data) Y[i] = Y[i] + y*x[i]; } } - + simeq(n, A, Y, C); - + } /* end fit_file */ void write_HWtab_bin(ivrm_parm_data_t* i_ivrm_parms, @@ -1129,11 +1625,11 @@ void write_HWtab_bin(ivrm_parm_data_t* i_ivrm_parms, double Ical[40][40]; double Iratio[40][40]; double Iratio_clip; - uint8_t Iratio_int[40][40]; + uint8_t Iratio_int[40][40]; uint32_t temp; uint8_t ratio_val; uint8_t idx; - + NUM_VIN = i_ivrm_parms->vin_entries_per_vds; NUM_VDS = i_ivrm_parms->vds_region_entries; VIN_MIN = 600; @@ -1142,7 +1638,7 @@ void write_HWtab_bin(ivrm_parm_data_t* i_ivrm_parms, TEMP_UPLIFT = 1.1; for(i=0; i<NUM_VIN; i++) { Vin[i] = VIN_MIN + i * 25; } - + Vds[0]=VDS_MIN; for(i=1; i<NUM_VDS; i++) { temp=(int) (Vds[i-1]*1.25/6.25); @@ -1154,29 +1650,29 @@ void write_HWtab_bin(ivrm_parm_data_t* i_ivrm_parms, if(Vin[i]-Vds[j]>=700) { Ical[i][j] = C[0] + C[1]*Vin[i] + C[2]*Vds[j] + C[3]*Vin[i]*Vds[j]; // compute cal current Iratio[i][j] = TEMP_UPLIFT * LSB_CURRENT / Ical[i][j]; - + // clip at 3.875 and use for both temp calculations - Iratio_clip = (Iratio[i][j]+1/16>3.875 ? 3.875 : Iratio[i][j]+1/16); -// bug temp = (int) (Iratio[i][j]+1/16>3.875 ? 3.875 : Iratio[i][j]+1/16); - temp = (int) Iratio_clip; + Iratio_clip = (Iratio[i][j]+1/16>3.875 ? 3.875 : Iratio[i][j]+1/16); +// bug temp = (int) (Iratio[i][j]+1/16>3.875 ? 3.875 : Iratio[i][j]+1/16); + temp = (int) Iratio_clip; ratio_val = 0; ratio_val = (temp << 3) & 0x018; // jwy shift temp left 3 and clear out lower 3 bits - this gets bits 0:1 of value temp = (int) ( (Iratio_clip - temp)*8 + 0.5); temp = temp > 7 ? 7 : temp; // bug fix - clip to 7 if overflow ratio_val = (temp & 0x07)| ratio_val; // jwy OR lower 3 bits of temp with upper 2 bits already in 0:1 - this merges bits 2:4 with 0:1 for final value - Iratio_int[i][j] = ratio_val; + Iratio_int[i][j] = ratio_val; } else { Iratio[i][j] = 0; Iratio_int[i][j] = 0; } } } - + // fill in Vin table with Iratio data for (i=0; i<NUM_VDS; i++) { // 16 rows - + for(j=0; j<4; j++) { // 32 cols - idx = (i*4) + j; + idx = (i*4) + j; pss->lpsa.vdsvin[idx].fields.pfet0 = Iratio_int[j*8][i]; pss->lpsa.vdsvin[idx].fields.pfet1 = Iratio_int[(j*8)+1][i]; pss->lpsa.vdsvin[idx].fields.pfet2 = Iratio_int[(j*8)+2][i]; @@ -1184,10 +1680,15 @@ void write_HWtab_bin(ivrm_parm_data_t* i_ivrm_parms, pss->lpsa.vdsvin[idx].fields.pfet4 = Iratio_int[(j*8)+4][i]; pss->lpsa.vdsvin[idx].fields.pfet5 = Iratio_int[(j*8)+5][i]; pss->lpsa.vdsvin[idx].fields.pfet6 = Iratio_int[(j*8)+6][i]; - pss->lpsa.vdsvin[idx].fields.pfet7 = Iratio_int[(j*8)+7][i]; - + pss->lpsa.vdsvin[idx].fields.pfet7 = Iratio_int[(j*8)+7][i]; + // Byte reverse the entry into the image. - pss->lpsa.vdsvin[idx].value = revle64(pss->lpsa.vdsvin[idx].value); + pss->lpsa.vdsvin[idx].value = revle64(pss->lpsa.vdsvin[idx].value); } - } + } } /* end fit_file */ + + +#ifdef __cplusplus +} // end extern C +#endif diff --git a/src/usr/hwpf/hwp/pstates/pstates/pstate_tables.h b/src/usr/hwpf/hwp/pstates/pstates/pstate_tables.h index 49d56eff3..928db5f10 100755 --- a/src/usr/hwpf/hwp/pstates/pstates/pstate_tables.h +++ b/src/usr/hwpf/hwp/pstates/pstates/pstate_tables.h @@ -5,9 +5,9 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2013,2014 */ -/* [+] International Business Machines Corp. */ +/* Contributors Listed Below - COPYRIGHT 2013,2015 */ /* [+] Google Inc. */ +/* [+] International Business Machines Corp. */ /* */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ @@ -26,7 +26,8 @@ #ifndef __PSTATE_TABLES_H__ #define __PSTATE_TABLES_H__ -// $Id: pstate_tables.h,v 1.10 2014/07/03 02:57:52 daviddu Exp $ +// $Id: pstate_tables.h,v 1.12 2015/06/01 19:02:17 stillgs Exp $ + /// \file pstate_tables.h /// \brief Code used to generate Pstate tables from real or imagined chip @@ -36,10 +37,11 @@ // Constants associated with VRM stepping -#define PSTATE_STEPSIZE_MAX 127 -#define VRM_STEPDELAY_RANGE_BITS 4 -#define LOG2_VRM_STEPDELAY_DIVIDER 3 -#define VRM_STEPDELAY_MAX 1600000 +#define PSTATE_STEPSIZE_MAX 127 +#define VRM_STEPDELAY_RANGE_BITS 4 +#define LOG2_VRM_STEPDELAY_DIVIDER 3 +#define VRM_STEPDELAY_MAX 1600000 +#define MAX_ACTIVE_CORES 12 #ifndef __ASSEMBLER__ @@ -48,32 +50,10 @@ extern "C" { #endif -/// A VPD operating point -/// -/// VPD operating points are stored without load-line correction. Frequencies -/// are in MHz, voltages are specified in units of 5mV, and characterization -/// currents are specified in units of 500mA. -/// -/// \bug The assumption is that the 'maxreg' points for the iVRM will also be -/// supplied in the VPD in units of 5mv. If they are supplied in some other -/// form then chip_characterization_create() will need to be modified. - -typedef struct { - - uint32_t vdd_5mv; - uint32_t vcs_5mv; - uint32_t vdd_maxreg_5mv; - uint32_t vcs_maxreg_5mv; - uint32_t idd_500ma; - uint32_t ics_500ma; - uint32_t frequency_mhz; - -} VpdOperatingPoint; - - /// An internal operating point /// -/// Internal operating points include characterization and load-line corrected +/// Internal operating points include characterization (both the original, +/// unbiased values and biased by external attributes) and load-line corrected /// voltages for the external VRM. For the internal VRM, effective e-voltages /// and maxreg voltages are stored. All voltages are stored as /// uV. Characterization currents are in mA. Frequencies are in KHz. The @@ -83,9 +63,11 @@ typedef struct { typedef struct { uint32_t vdd_uv; - uint32_t vcs_uv; + uint32_t vcs_uv; uint32_t vdd_corrected_uv; uint32_t vcs_corrected_uv; + uint32_t vdd_corrected_wof_uv[MAX_ACTIVE_CORES]; + uint32_t vcs_corrected_wof_uv[MAX_ACTIVE_CORES]; uint32_t vdd_ivrm_effective_uv; uint32_t vcs_ivrm_effective_uv; uint32_t vdd_maxreg_uv; @@ -124,9 +106,11 @@ typedef struct { typedef struct { VpdOperatingPoint *vpd; + VpdOperatingPoint *vpd_unbiased; OperatingPoint *ops; OperatingPointParameters *parameters; - int points; + uint32_t points; + uint32_t max_cores; // Needed for WOF } ChipCharacterization; @@ -145,11 +129,12 @@ chip_characterization_create(ChipCharacterization *characterization, VpdOperatingPoint *vpd, OperatingPoint *ops, OperatingPointParameters *parameters, - int points); + uint32_t points); int gpst_create(GlobalPstateTable *gpst, - ChipCharacterization *characterization, + ChipCharacterization *characterization, + WOFElements *wof, int pstate_stepsize, int evrm_delay_ns); @@ -201,9 +186,12 @@ void fit_file(int n, void write_HWtab_bin(ivrm_parm_data_t* i_ivrm_parms, double C[], PstateSuperStructure* pss); + +int +vid_mod_entry_create(WOFElements *wof, uint32_t entry, uint32_t cores, OperatingPoint *op); #ifdef __cplusplus -} // extern "C" +} // end extern C #endif #endif // __ASSEMBLER__ diff --git a/src/usr/hwpf/hwp/pstates/pstates/pstates.c b/src/usr/hwpf/hwp/pstates/pstates/pstates.c index 760ef0ad3..863d00634 100755 --- a/src/usr/hwpf/hwp/pstates/pstates/pstates.c +++ b/src/usr/hwpf/hwp/pstates/pstates/pstates.c @@ -5,7 +5,9 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* COPYRIGHT International Business Machines Corp. 2013,2014 */ +/* Contributors Listed Below - COPYRIGHT 2013,2015 */ +/* [+] International Business Machines Corp. */ +/* */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ /* you may not use this file except in compliance with the License. */ @@ -20,7 +22,7 @@ /* permissions and limitations under the License. */ /* */ /* IBM_PROLOG_END_TAG */ -// $Id: pstates.c,v 1.7 2014/02/18 16:07:35 jimyac Exp $ +// $Id: pstates.c,v 1.9 2015/06/01 19:02:17 stillgs Exp $ /// \file pstates.c /// \brief Pstate routines required by OCC product firmware @@ -29,6 +31,10 @@ #include "pgp_common.h" #include "pstates.h" +#ifdef __cplusplus +extern "C" { +#endif + /// Validate a VRM11 VID code /// /// \param vid A VRM11 VID @@ -410,3 +416,6 @@ int pstate_minmax_chk (const GlobalPstateTable* gpst, return rc; } +#ifdef __cplusplus +} // end extern C +#endif diff --git a/src/usr/hwpf/hwp/pstates/pstates/pstates.h b/src/usr/hwpf/hwp/pstates/pstates/pstates.h index 8c5ea2b6d..fd0e876ea 100755 --- a/src/usr/hwpf/hwp/pstates/pstates/pstates.h +++ b/src/usr/hwpf/hwp/pstates/pstates/pstates.h @@ -5,9 +5,9 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2013,2014 */ -/* [+] International Business Machines Corp. */ +/* Contributors Listed Below - COPYRIGHT 2013,2015 */ /* [+] Google Inc. */ +/* [+] International Business Machines Corp. */ /* */ /* */ /* Licensed under the Apache License, Version 2.0 (the "License"); */ @@ -26,17 +26,13 @@ #ifndef __PSTATES_H__ #define __PSTATES_H__ -// $Id: pstates.h,v 1.11 2014/05/27 15:33:49 daviddu Exp $ +// $Id: pstates.h,v 1.14 2015/06/01 19:02:17 stillgs Exp $ /// \file pstates.h /// \brief Pstate structures and support routines for OCC product firmware #include "pgp_common.h" -#ifdef __cplusplus -extern "C" { -#endif - //////////////////////////////////////////////////////////////////////////// // Global and Local Pstate Tables //////////////////////////////////////////////////////////////////////////// @@ -52,7 +48,7 @@ extern "C" { #define LOCAL_PSTATE_ARRAY_ENTRIES 32 /// The VDS/VIN table has 32 x 64-bit entries -#define VDSVIN_ARRAY_ENTRIES 64 +#define VDSVIN_ARRAY_ENTRIES 64 /// The VRM-11 VID base voltage in micro-Volts #define VRM11_BASE_UV 1612500 @@ -66,9 +62,45 @@ extern "C" { /// The iVID step as an unsigned number (micro-Volts) #define IVID_STEP_UV 6250 -/// CPM Inflection Points +/// CPM Inflection Points #define CPM_RANGES 8 +/// VPD #V Operating Points +#define VPD_PV_POINTS 4 +#define VPD_PV_ORDER_STR {"PowerSave", "Nominal ", "Turbo ", "UltraTurbo"} +#define POWERSAVE 0 +#define NOMINAL 1 +#define TURBO 2 +#define ULTRA 3 + +/// IDDQ readings +#define CORE_IDDQ_MEASUREMENTS 6 +#define CHIP_IDDQ_MEASUREMENTS 1 + +#define CORE_IDDQ_ARRAY_VOLTAGES {0.80, 0.90, 1.00, 1.10, 1.20, 1.25} +#define CHIP_IDDQ_ARRAY_VOLTAGES {1.10} + +/// Iddq LRPx and CRPx elements +#define LRP_IDDQ_RECORDS CORE_IDDQ_MEASUREMENTS +#define CRP_IDDQ_RECORDS CHIP_IDDQ_MEASUREMENTS +#define IDDQ_READINGS_PER_IQ 2 + +/// LRPx mapping to Core measurements 1 2 3 4 5 6 +/// Index 0 1 2 3 4 5 +#define CORE_IDDQ_MEASUREMENTS_ORDER { 1, 2, 3, 4, 5, 0} +#define CORE_IDDQ_MEASUREMENT_VOLTAGES {"0.90", "1.00", "1.10", "1.20", "1.25", "0.80"} +#define CORE_IDDQ_VALIDITY_CHECK { 1, 1, 1, 1, 1, 0} +#define CORE_IDDQ_VALID_SECOND { 1, 1, 1, 1, 1, 0} + +// CRPx mapping to Chip measurements 0 +#define CHIP_IDDQ_MEASUREMENTS_ORDER { 0 } +#define CHIP_IDDQ_MEASUREMENT_VOLTAGES {"1.10"} +#define CHIP_IDDQ_VALID_SECOND { 0 } + +/// WOF Items +#define NUM_ACTIVE_CORES 12 +#define MAX_UT_PSTATES 64 // Oversized + // Error/Panic codes for support routines #define VRM11_INVALID_VOLTAGE 0x00876101 @@ -93,8 +125,8 @@ extern "C" { #define GPST_BUG 0x00477806 #define GPST_PSTATE_GT_GPST_PMAX 0x00477807 -#define LPST_INVALID_OBJECT 0x00477901 -#define LPST_GPST_WARNING 0x00477902 +#define LPST_INVALID_OBJECT 0x00477901 +#define LPST_GPST_WARNING 0x00477902 #define LPST_INCR_CLIP_ERROR 0x00477903 /// PstateSuperStructure Magic Number @@ -102,9 +134,9 @@ extern "C" { /// This magic number identifies a particular version of the /// PstateSuperStructure and its substructures. The version number should be /// kept up to date as changes are made to the layout or contents of the -/// structure. +/// structure. -#define PSTATE_SUPERSTRUCTURE_MAGIC 0x5053544154453033ull /* PSTATE03 */ +#define PSTATE_SUPERSTRUCTURE_MAGIC 0x5053544154453034ull /* PSTATE04 */ /// \defgroup pstate_options Pstate Options @@ -135,10 +167,18 @@ extern "C" { /// to come up at a low frequency. #define PSTATE_FORCE_INITIAL_PMIN 0x10 +/// Flag to indicated that the 0.8V readings in the IDDQ Table are valid +#define PSTATE_IDDQ_0P80V_VALID 0x20 +#define PSTATE_IDDQ_0P80V_INVALID ~PSTATE_IDDQ_0P80V_VALID + /// @} #ifndef __ASSEMBLER__ +#ifdef __cplusplus +extern "C" { +#endif + #include <stdint.h> #include <p8_ivrm.H> @@ -220,7 +260,7 @@ typedef union lpst_entry { uint64_t vdd_eco_pwrratio : 6; uint64_t vcs_eco_pwrratio : 6; uint64_t ps1_vid_incr : 3; - uint64_t ps2_vid_incr : 3; + uint64_t ps2_vid_incr : 3; uint64_t ps3_vid_incr : 3; uint64_t reserved47 : 7; uint64_t inc_step : 3; @@ -232,7 +272,7 @@ typedef union lpst_entry { uint64_t inc_step : 3; uint64_t reserved47 : 7; uint64_t ps3_vid_incr : 3; - uint64_t ps2_vid_incr : 3; + uint64_t ps2_vid_incr : 3; uint64_t ps1_vid_incr : 3; uint64_t vcs_eco_pwrratio : 6; uint64_t vdd_eco_pwrratio : 6; @@ -263,29 +303,29 @@ typedef union vdsvin_entry { #ifdef _BIG_ENDIAN uint64_t ivid0 : 7; uint64_t ivid1 : 7; - uint64_t reserved14 : 2; - uint64_t pfet0 : 5; - uint64_t pfet1 : 5; - uint64_t pfet2 : 5; - uint64_t pfet3 : 5; - uint64_t pfet4 : 5; - uint64_t pfet5 : 5; - uint64_t pfet6 : 5; + uint64_t reserved14 : 2; + uint64_t pfet0 : 5; + uint64_t pfet1 : 5; + uint64_t pfet2 : 5; + uint64_t pfet3 : 5; + uint64_t pfet4 : 5; + uint64_t pfet5 : 5; + uint64_t pfet6 : 5; uint64_t pfet7 : 5; - uint64_t reserved_56 : 8; + uint64_t reserved_56 : 8; #else uint64_t reserved_56 : 8; - uint64_t pfet7 : 5; - uint64_t pfet6 : 5; - uint64_t pfet5 : 5; - uint64_t pfet4 : 5; - uint64_t pfet3 : 5; - uint64_t pfet2 : 5; - uint64_t pfet1 : 5; - uint64_t pfet0 : 5; - uint64_t reserved14 : 2; - uint64_t ivid1 : 7; - uint64_t ivid0 : 7; + uint64_t pfet7 : 5; + uint64_t pfet6 : 5; + uint64_t pfet5 : 5; + uint64_t pfet4 : 5; + uint64_t pfet3 : 5; + uint64_t pfet2 : 5; + uint64_t pfet1 : 5; + uint64_t pfet0 : 5; + uint64_t reserved14 : 2; + uint64_t ivid1 : 7; + uint64_t ivid0 : 7; #endif // _BIG_ENDIAN } fields; } vdsvin_entry_t; @@ -397,12 +437,31 @@ typedef struct { /// The Pstate for minimum core frequency in the system, defined by MRW uint8_t pfloor; + + /// The Pstate representing the Turbo VPD point + Pstate turbo_ps; + + /// The Pstate representing the Nominal VPD point + Pstate nominal_ps; + + /// The Pstate representing the PowerSave VPD point + Pstate powersave_ps; + + /// The Pstate within the GPST which is the maximum for which iVRMs are + /// defined. This allows WOF Pstate and iVRM Pstates to be non-overlapping + /// to simplify characterization. + Pstate ivrm_max_ps; + + /// The number of entries over which iVRM enablement is possible. The + /// starting entry is PMin. + uint8_t ivrm_entries; + } GlobalPstateTable; /// This macro creates a properly-aligned Global Pstate table structure as a -/// static initialization. +/// static initialization. #define GLOBAL_PSTATE_TABLE(x) \ GlobalPstateTable x \ @@ -482,12 +541,12 @@ typedef struct { /// CPM Pstate ranges per mode /// /// These Pstate range specifications apply to all chiplets operating in the -/// same mode. +/// same mode. typedef union { /// Forces alignment - uint64_t quad[2]; + uint64_t quad[2]; struct { @@ -510,13 +569,181 @@ typedef union { /// This is the "CPmax" for the mode. The "CPmin" for this /// mode is the value of inflectionPoint[valid_ranges - 1]. Pstate pMax; - + uint8_t pad[6]; }; } CpmPstateModeRanges; +/// A VPD operating point +/// +/// VPD operating points are stored without load-line correction. Frequencies +/// are in MHz, voltages are specified in units of 5mV, and characterization +/// currents are specified in units of 500mA. +/// +/// \bug The assumption is that the 'maxreg' points for the iVRM will also be +/// supplied in the VPD in units of 5mv. If they are supplied in some other +/// form then chip_characterization_create() will need to be modified. + +typedef struct { + + uint32_t vdd_5mv; + uint32_t vcs_5mv; + uint32_t vdd_maxreg_5mv; + uint32_t vcs_maxreg_5mv; + uint32_t idd_500ma; + uint32_t ics_500ma; + uint32_t frequency_mhz; + +} VpdOperatingPoint; + +/// System Power Distribution Paramenters +/// +/// Parameters set by system design that influence the power distribution +/// for a rail to the processor module. This values are typically set in the +/// system machine readable workbook and are used in the generation of the +/// Global Pstate Table. This values are carried in the Pstate SuperStructure +/// for use and/or reference by OCC firmware (eg the WOF algorithm) + +typedef struct { + + /// Loadline + /// Impedance (binary microOhms) of the load line from a processor VDD VRM + /// to the Processor Module pins. + uint32_t loadline_uohm; + + /// Distribution Loss + /// Impedance (binary in microOhms) of the VDD distribution loss sense point + /// to the circuit. + uint32_t distloss_uohm; + + /// Distribution Offset + /// Offset voltage (binary in microvolts) to apply to the rail VRM + /// distribution to the processor module. + uint32_t distoffset_uv; + +} SysPowerDistParms; + + + +/// IDDQ Reading Type +/// Each entry is 2 bytes. The values are in 10mA units; this allow for a +/// maximum value of 655.36A represented. +/// +typedef uint16_t iddq_entry_t; + +/// IDDQ Reading +/// +/// Structure with "raw" and "temperature corrected" values. See VPD +/// documentation for the correction function that is applied to the raw +/// value to load the corrected value. +/// +typedef union { + uint32_t value; + struct { +#ifdef _BIG_ENDIAN + iddq_entry_t iddq_raw_value; + iddq_entry_t iddq_corrected_value; +#else + iddq_entry_t iddq_corrected_value; + iddq_entry_t iddq_raw_value; +#endif // _BIG_ENDIAN + } fields; + +} IddqReading; + +/// Iddq Table +/// +/// A set of arrays of leakage values (Iddq) collected at various voltage +/// conditions during manufacturing test that will feed into the Workload +/// Optimized Frequency algorithms on the OCC. These values are not installed +/// in any hardware facilities. +/// +typedef struct { + + /// IDDQ version + uint8_t iddq_version; + + /// VDD IDDQ readings + IddqReading iddq_vdd[CORE_IDDQ_MEASUREMENTS]; + + /// VCS IDDQ readings + IddqReading iddq_vcs[CORE_IDDQ_MEASUREMENTS]; + + /// VIO IDDQ readings + IddqReading iddq_vio[CHIP_IDDQ_MEASUREMENTS]; + +} IddqTable; + + + +/// UltraTurbo Segment VIDs by Core Count +typedef struct { + + /// Number of Segment Pstates + uint8_t ut_segment_pstates; + + /// Maximum number of core possibly active + uint8_t ut_max_cores; + + /// VDD VID modification + /// 1 core active = offset 0 + /// 2 cores active = offset 1 + /// ... + /// 12 cores active = offset 11 + uint8_t ut_segment_vdd_vid[MAX_UT_PSTATES][NUM_ACTIVE_CORES]; + + /// VCS VID modification + /// 1 core active = offset 0 + /// 2 cores active = offset 1 + /// ... + /// 12 cores active = offset 11 + uint8_t ut_segment_vcs_vid[MAX_UT_PSTATES][NUM_ACTIVE_CORES]; + +} VIDModificationTable; + +/// Workload Optimized Frequency (WOF) Elements +/// +/// Structure defining various control elements needed by the WOF algorithm +/// firmware running on the OCC. +/// +typedef struct { + + /// WOF Enablement + uint8_t wof_enabled; + + /// Operating points + /// + /// VPD operating points are stored without load-line correction. Frequencies + /// are in MHz, voltages are specified in units of 5mV, and currents are + /// in units of 500mA. + VpdOperatingPoint operating_points[VPD_PV_POINTS]; + + /// Loadlines and Distribution values for the VDD rail + SysPowerDistParms vdd_sysparm; + + /// Loadlines and Distribution values for the VCS rail + SysPowerDistParms vcs_sysparm; + + /// TDP<>RDP Current Factor + /// Value read from ??? VPD + /// Defines the scaling factor that converts current (amperage) value from + /// the Thermal Design Point to the Regulator Design Point (RDP) as input + /// to the Workload Optimization Frequency (WOF) OCC algorithm. + /// + /// This is a ratio value and has a granularity of 0.01 decimal. Data + /// is held in hexidecimal (eg 1.22 is represented as 122 and then converted + /// to hex 0x7A). + uint32_t tdp_rdp_factor; + + /// UltraTurbo Segment VIDs by Core Count + VIDModificationTable ut_vid_mod; + + uint8_t pad[4]; + +} WOFElements; + /// The layout of the data created by the Pstate table creation firmware /// /// This structure is only used for passing Pstate data from the FSP into OCC, @@ -538,13 +765,19 @@ typedef struct { /// Local Pstate Array LocalPstateArray lpsa; - + /// Resonant Clocking Setup ResonantClockingSetup resclk; - + /// CPM Pstate ranges CpmPstateModeRanges cpmranges; - + + /// Iddq Table + IddqTable iddq; + + /// WOF Controls + WOFElements wof; + } PstateSuperStructure; @@ -561,25 +794,25 @@ int bias_vid11(Vid11 vid, int bias, Vid11* biased_fcode); int -gpst_entry(const GlobalPstateTable* gpst, - const Pstate pstate, +gpst_entry(const GlobalPstateTable* gpst, + const Pstate pstate, const int bias, gpst_entry_t* entry); -int -freq2pState (const GlobalPstateTable* gpst, - const uint32_t freq_khz, +int +freq2pState (const GlobalPstateTable* gpst, + const uint32_t freq_khz, Pstate* pstate); - + int -gpst_vdd2pstate(const GlobalPstateTable* gpst, - const uint8_t vdd, +gpst_vdd2pstate(const GlobalPstateTable* gpst, + const uint8_t vdd, Pstate* pstate, gpst_entry_t* entry); int -pstate_minmax_chk (const GlobalPstateTable* gpst, +pstate_minmax_chk (const GlobalPstateTable* gpst, Pstate* pstate); /// Return the Pmin value associated with a GlobalPstateTable @@ -613,7 +846,7 @@ lpst_pmax(const LocalPstateArray* lpsa) } #ifdef __cplusplus -} // extern "C" +} // end extern C #endif #endif /* __ASSEMBLER__ */ diff --git a/src/usr/hwpf/hwp/pstates/pstates_common.mk b/src/usr/hwpf/hwp/pstates/pstates_common.mk index bded93134..98dddd856 100644 --- a/src/usr/hwpf/hwp/pstates/pstates_common.mk +++ b/src/usr/hwpf/hwp/pstates/pstates_common.mk @@ -54,6 +54,10 @@ OBJS += pstate_tables.o OBJS += freqVoltageSvc.o OBJS += proc_set_max_pstate.o +## allow FAPI macros in c files +CFLAGS += -D __FAPI +CC_OVERRIDE = 1 + ## NOTE: add a new directory onto the vpaths when you add a new HWP ##@ VPATH += ${ROOTPATH}/src/usr/hwpf/hwp/??? VPATH += ${ROOTPATH}/src/usr/hwpf/hwp/pstates/pstates |