diff options
author | Thi Tran <thi@us.ibm.com> | 2013-10-02 10:31:04 -0500 |
---|---|---|
committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2013-10-04 15:40:34 -0500 |
commit | 8cddf17c6fdc5810f7cf244012afe19a7bcbd77d (patch) | |
tree | 8c7495fd83697e5d2f9f7fdac70b8b51b93f3fc2 /src/usr/hwpf/hwp/pstates/pstates | |
parent | f67e73208f2e6db20b35efaedaf15a4d669c2869 (diff) | |
download | talos-hostboot-8cddf17c6fdc5810f7cf244012afe19a7bcbd77d.tar.gz talos-hostboot-8cddf17c6fdc5810f7cf244012afe19a7bcbd77d.zip |
INITPROC: Hostboot - from defect SW224356 - PSTATE procedures
Change-Id: I5358dab2f24f26054fb004ff980c9fe4638cff6c
CMVC-Coreq:896229
CQ:SW224356
Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/6446
Tested-by: Jenkins Server
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src/usr/hwpf/hwp/pstates/pstates')
-rwxr-xr-x | src/usr/hwpf/hwp/pstates/pstates/lab_pstates.c | 192 | ||||
-rwxr-xr-x | src/usr/hwpf/hwp/pstates/pstates/lab_pstates.h | 16 | ||||
-rwxr-xr-x | src/usr/hwpf/hwp/pstates/pstates/p8_build_pstate_datablock.C | 776 | ||||
-rwxr-xr-x | src/usr/hwpf/hwp/pstates/pstates/p8_build_pstate_datablock.H | 52 | ||||
-rwxr-xr-x | src/usr/hwpf/hwp/pstates/pstates/p8_build_pstate_datablock_errors.xml | 35 | ||||
-rw-r--r-- | src/usr/hwpf/hwp/pstates/pstates/p8_ivrm.H | 110 | ||||
-rwxr-xr-x | src/usr/hwpf/hwp/pstates/pstates/pstate_tables.c | 634 | ||||
-rwxr-xr-x | src/usr/hwpf/hwp/pstates/pstates/pstate_tables.h | 47 | ||||
-rwxr-xr-x | src/usr/hwpf/hwp/pstates/pstates/pstates.c | 31 | ||||
-rwxr-xr-x | src/usr/hwpf/hwp/pstates/pstates/pstates.h | 112 |
10 files changed, 1691 insertions, 314 deletions
diff --git a/src/usr/hwpf/hwp/pstates/pstates/lab_pstates.c b/src/usr/hwpf/hwp/pstates/pstates/lab_pstates.c index 2e7767927..fe545b7a5 100755 --- a/src/usr/hwpf/hwp/pstates/pstates/lab_pstates.c +++ b/src/usr/hwpf/hwp/pstates/pstates/lab_pstates.c @@ -20,7 +20,7 @@ /* Origin: 30 */ /* */ /* IBM_PROLOG_END_TAG */ -// $Id: lab_pstates.c,v 1.7 2013/06/12 20:01:35 mjjones Exp $ +// $Id: lab_pstates.c,v 1.8 2013/08/13 17:12:54 jimyac Exp $ /// \file lab_pstates.c /// \brief Lab-only (as opposed to product-procedure) support for Pstates. @@ -97,7 +97,7 @@ vrm112vuv(uint8_t vrm11_vid, uint32_t *v_uv) int vuv2ivid(uint32_t v_uv, int round, uint8_t *ivid) -{ +{ int rc; int32_t offset, vid; @@ -105,7 +105,7 @@ vuv2ivid(uint32_t v_uv, int round, uint8_t *ivid) vid = offset / IVID_STEP_UV; if (((offset % IVID_STEP_UV) != 0) && (round >= 0)) { - vid++; + vid++; } *ivid = vid; @@ -114,10 +114,9 @@ vuv2ivid(uint32_t v_uv, int round, uint8_t *ivid) } else { rc = 0; } - return rc; + return rc; } - /// Convert an iVID code to a voltage in microvolts int @@ -141,21 +140,24 @@ sprintf_10uv(char *s, uint32_t v_uv) return sprintf(s, "%d.%05d", v_uv / 1000000, (v_uv % 1000000) / 10); } -/// Format an IVID code as 10 microvolts into a user-supplied string. The -/// string \a s must be able to store at least FORMAT_10UV_STRLEN characters. +#ifdef FAPIECMD + +/// Format a voltage in microvolts as 10 microvolts to a stream. int -sprintf_ivid(char *s, uint8_t ivid) +fprintf_10uv(FILE *stream, uint32_t v_uv) { int rc; - uint32_t v_uv; + char s[FORMAT_10UV_STRLEN]; - if ((rc = ivid2vuv(ivid, &v_uv)) != 0) { - return rc; + rc = sprintf_10uv(s, v_uv); + if (rc > 0) { + rc = fputs(s, stream); } - return sprintf_10uv(s, v_uv); + return rc; } + /// Format a VRM-11 VID code as 10 microvolts into a user-supplied string. The /// string \a s must be able to store at least FORMAT_10UV_STRLEN characters. @@ -173,17 +175,16 @@ sprintf_vrm11(char *s, uint8_t vrm11) return rc; } -#ifdef FAPIECMD -/// Format a voltage in microvolts as 10 microvolts to a stream. +/// Format a VRM-11 VID code as 10 microvolts to a stream. int -fprintf_10uv(FILE *stream, uint32_t v_uv) +fprintf_vrm11(FILE *stream, uint8_t vrm11) { int rc; char s[FORMAT_10UV_STRLEN]; - rc = sprintf_10uv(s, v_uv); + rc = sprintf_vrm11(s, vrm11); if (rc > 0) { rc = fputs(s, stream); } @@ -191,19 +192,19 @@ fprintf_10uv(FILE *stream, uint32_t v_uv) } -/// Format a VRM-11 VID code as 10 microvolts to a stream. +/// Format an IVID code as 10 microvolts into a user-supplied string. The +/// string \a s must be able to store at least FORMAT_10UV_STRLEN characters. int -fprintf_vrm11(FILE *stream, uint8_t vrm11) +sprintf_ivid(char *s, uint8_t ivid) { int rc; - char s[FORMAT_10UV_STRLEN]; + uint32_t v_uv; - rc = sprintf_vrm11(s, vrm11); - if (rc > 0) { - rc = fputs(s, stream); - } + if ((rc = ivid2vuv(ivid, &v_uv)) != 0) { return rc; + } + return sprintf_10uv(s, v_uv); } @@ -400,32 +401,154 @@ void lpsa_print(FILE* stream, LocalPstateArray* lpsa) { int i; + uint8_t entries; + uint8_t entries_div4; + char ivid_vdd_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, "Local Pstate Array @ %p\n", lpsa); 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_rising, lpsa->stepdelay_lowering); + 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; + + if ( entries % 4 != 0) + entries_div4++; + + 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); + + ivid_vcs = lpst_entry.fields.ivid_vcs; + sprintf_ivid(ivid_vcs_str, ivid_vcs); + + fprintf(stream, + "%2u " + "0x%02x %s " + "0x%02x %s " + "%-9u %-9u %-9u %-9u " + "%-8u %-8u %-8u " + "%-9u %-9u \n", + i, + ivid_vdd, ivid_vdd_str, + ivid_vcs, ivid_vcs_str, + (uint8_t)lpst_entry.fields.vdd_core_pwrratio, + (uint8_t)lpst_entry.fields.vcs_core_pwrratio, + (uint8_t)lpst_entry.fields.vdd_eco_pwrratio, + (uint8_t)lpst_entry.fields.vcs_eco_pwrratio, + (uint8_t)lpst_entry.fields.ps1_vid_incr, + (uint8_t)lpst_entry.fields.ps2_vid_incr, + (uint8_t)lpst_entry.fields.ps3_vid_incr, + (uint8_t)lpst_entry.fields.inc_step, + (uint8_t)lpst_entry.fields.dec_step); + } - fprintf(stream, "Array :\n"); - for (i = 0; i < LOCAL_PSTATE_ARRAY_ENTRIES; i+= 4) { - fprintf(stream, " 0x%016llx 0x%016llx 0x%016llx 0x%016llx\n", - (unsigned long long)(lpsa->pstate[i].value), - (unsigned long long)(lpsa->pstate[i + 1].value), - (unsigned long long)(lpsa->pstate[i + 2].value), - (unsigned long long)(lpsa->pstate[i + 3].value)); + fprintf(stream, + "---------------------------------------------------------------------------------------------------------------------\n\n"); + + fprintf(stream, + "--------------------------------\n"); + fprintf(stream, + "VDS\n"); + fprintf(stream, + " I beg_offset end_offset \n" + "--------------------------------\n"); + + for (i = 15 ; i >= 0; i--) { + vdsvin_entry.value = revle64(lpsa->vdsvin[i].value); + + fprintf(stream, + "%2u " + "%-10u " + "%-10u \n", + i, + (uint8_t)vdsvin_entry.fields.ivid0, + (uint8_t)vdsvin_entry.fields.ivid1); } fprintf(stream, - "---------------------------------------------------------------------------------------------------------\n"); + "--------------------------------\n\n"); + + + fprintf(stream, + "-----------------------------------------------------\n"); + fprintf(stream, + "VIN\n"); + fprintf(stream, + " I ptef0 pfet1 pfet2 pfet3 pfet4 pfet5 pfet6 pfet7\n" + "-----------------------------------------------------\n"); + + 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"); } +/// Print CPM Pstate Range structure on a given stream +/// +/// \param stream The output stream +/// +/// \param cpmrange The CPM Pstate Range structure to print + +void +cpmrange_print(FILE* stream, CpmPstateModeRanges* cpmrange) +{ + int i; + + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\n"); + fprintf(stream, "CPM Pstate Range @ %p\n", cpmrange); + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\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", + i, cpmrange->inflectionPoint[i]); + } + + fprintf(stream, " CPM Pmax : %d\n", + cpmrange->pMax); + + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\n"); +} /// Print a Resonant Clocking Setup structure on a given stream /// @@ -481,6 +604,5 @@ pss_print(FILE* stream, PstateSuperStructure* pss) "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); } -#endif // FAPIECMD - +#endif // FAPIECMD diff --git a/src/usr/hwpf/hwp/pstates/pstates/lab_pstates.h b/src/usr/hwpf/hwp/pstates/pstates/lab_pstates.h index 5a1b614ca..cc2252e8f 100755 --- a/src/usr/hwpf/hwp/pstates/pstates/lab_pstates.h +++ b/src/usr/hwpf/hwp/pstates/pstates/lab_pstates.h @@ -23,7 +23,7 @@ #ifndef __LAB_PSTATES_H__ #define __LAB_PSTATES_H__ -// $Id: lab_pstates.h,v 1.4 2013/06/12 20:01:48 mjjones Exp $ +// $Id: lab_pstates.h,v 1.5 2013/08/13 17:12:56 jimyac Exp $ /// \file lab_pstates.h /// \brief Lab-only (as opposed to product-procedure) support for Pstates. @@ -66,19 +66,19 @@ ivid2vuv(uint8_t ivid, uint32_t *v_uv); int sprintf_10uv(char *s, uint32_t v_uv); +#ifdef FAPIECMD + int -sprintf_ivid(char *s, uint8_t ivid); +fprintf_10uv(FILE *stream, uint32_t v_uv); int sprintf_vrm11(char *s, uint8_t vrm11); -#ifdef FAPIECMD - int -fprintf_10uv(FILE *stream, uint32_t v_uv); +fprintf_vrm11(FILE *stream, uint8_t vrm11); int -fprintf_vrm11(FILE *stream, uint8_t vrm11); +sprintf_ivid(char *s, uint8_t ivid); int fprintf_ivid(FILE *stream, uint8_t ivid); @@ -90,10 +90,14 @@ void lpsa_print(FILE* stream, LocalPstateArray* lpsa); void +cpmrange_print(FILE* stream, CpmPstateModeRanges* cpmrange); + +void resclk_print(FILE* stream, ResonantClockingSetup* resclk); void pss_print(FILE* stream, PstateSuperStructure* pss); + #endif // FAPIECMD #endif // __ASSEMBLER__ 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 ba0d6be88..03f926b2c 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 @@ -20,7 +20,7 @@ /* Origin: 30 */ /* */ /* IBM_PROLOG_END_TAG */ -// $Id: p8_build_pstate_datablock.C,v 1.14 2013/06/12 20:05:23 mjjones Exp $ +// $Id: p8_build_pstate_datablock.C,v 1.22 2013/09/30 18:35:35 jimyac 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 @@ -60,8 +60,12 @@ using namespace fapi; // ---------------------------------------------------------------------- // Function prototypes // ---------------------------------------------------------------------- -ReturnCode proc_get_mvpd_data (const Target& i_target, uint32_t attr_mvpd_data[PV_D][PV_W]); -ReturnCode proc_get_attributes (const Target& i_target, AttributeList *attr_list); +ReturnCode proc_get_mvpd_data (const Target& i_target, uint32_t attr_mvpd_data[PV_D][PV_W], ivrm_mvpd_t *ivrm_mvpd); +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); + // ---------------------------------------------------------------------- // Function definitions // ---------------------------------------------------------------------- @@ -72,87 +76,53 @@ ReturnCode proc_get_attributes (const Target& i_target, AttributeList *attr_list /// \retval ERROR defined in xml ReturnCode -p8_build_pstate_datablock(const Target& i_target, PstateSuperStructure *io_pss) +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; - double freq_bias = 1.0; - double volt_bias_vdd = 1.0; - double volt_bias_vcs = 1.0; + 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; - uint32_t frequency_step_khz = 0; - uint32_t attr_mvpd_voltage_control[PV_D][PV_W]; - FAPI_INF("Executing p8_build_pstate_datablock ...."); - + // ------------------------- // get all attributes needed // ------------------------- l_rc = proc_get_attributes(i_target , &attr ); - if (l_rc) + if (l_rc) return l_rc; - - // ----------- - // get #V data - // ----------- + + // calculate pstate frequency step in Khz + frequency_step_khz = (attr.attr_freq_proc_refclock * 1000)/attr.attr_proc_dpll_divider; + + // ---------------- + // get #V & #M data + // ---------------- // clear array memset(attr_mvpd_voltage_control, 0, sizeof(attr_mvpd_voltage_control)); - - l_rc = proc_get_mvpd_data(i_target , attr_mvpd_voltage_control); - if (l_rc) - return l_rc; - - // ---------------------------------------------------- - // Check Valid Frequency and Voltage Biasing Attributes - // - cannot have both up and down bias set - // ---------------------------------------------------- - if (attr.attr_freq_bias_up > 0 && attr.attr_freq_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); - return l_rc; - } + memset(&ivrm_mvpd, 0, sizeof(ivrm_mvpd)); - if (attr.attr_voltage_ext_bias_up > 0 && attr.attr_voltage_ext_bias_down > 0) { - FAPI_ERR("**** ERROR : External Frequency bias up and down both defined"); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_EXT_VOLTAGE_BIAS_ERROR); + l_rc = proc_get_mvpd_data(i_target, attr_mvpd_voltage_control, &ivrm_mvpd); + if (l_rc) return l_rc; - } - if (attr.attr_voltage_int_bias_up > 0 && attr.attr_voltage_int_bias_down > 0) { - FAPI_ERR("**** ERROR : Internal Frequency bias up and down both defined"); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_INT_VOLTAGE_BIAS_ERROR); + // --------------------------------------------- + // process external and internal bias attributes + // --------------------------------------------- + l_rc = proc_get_extint_bias(attr_mvpd_voltage_control, &attr, &volt_int_vdd_bias, &volt_int_vcs_bias); + if (l_rc) return l_rc; - } - - // -------------------------------------------------------------------- - // Apply specified Frequency and Voltage Biasing to attr_mvpd_voltage_control - // - convert freq/voltage to double - // - compute biased freq/voltage and round - // - convert back to integer - // - align frequency to frequency_step_khz (attr_freq_proc_refclock/attr_proc_dpll_divider) - // - are (double) and (int) required??? - // -------------------------------------------------------------------- - frequency_step_khz = (attr.attr_freq_proc_refclock*1000)/attr.attr_proc_dpll_divider; - - freq_bias = 1.0 + (0.01 * (double)attr.attr_freq_bias_up) - (0.01 * (double)attr.attr_freq_bias_down); // at least one bias value is guaranteed to be 0 - volt_bias_vdd = 1.0 + (0.01 * (double)attr.attr_voltage_ext_bias_up) - (0.01 * (double)attr.attr_voltage_ext_bias_down); // at least one bias value is guaranteed to be 0 - volt_bias_vcs = 1.0 + (0.01 * (double)attr.attr_voltage_ext_bias_up) - (0.01 * (double)attr.attr_voltage_ext_bias_down); // at least one bias value is guaranteed to be 0 - - // loop over each bucket - for (i=0; i <= 4; i++) { - attr_mvpd_voltage_control[i][0] = (uint32_t) ((( (double)attr_mvpd_voltage_control[i][0]) * freq_bias) + 0.5); - - // align to frequency step as defined by attr_proc_refclk_frequency/attr_proc_dpll_divider - // jwy FIXME:caused float exception attr_mvpd_voltage_control[i][0] = (attr_mvpd_voltage_control[i][0] + (frequency_step_khz - (attr_mvpd_voltage_control[i][0]%frequency_step_khz))%frequency_step_khz); - - attr_mvpd_voltage_control[i][1] = (uint32_t) ((( (double)attr_mvpd_voltage_control[i][1]) * volt_bias_vdd) + 0.5); // vdd - attr_mvpd_voltage_control[i][3] = (uint32_t) ((( (double)attr_mvpd_voltage_control[i][3]) * volt_bias_vcs) + 0.5); // vcs - } // ----------------------------------------------- // populate VpdOperatingPoint with MVPD attributes @@ -169,7 +139,7 @@ p8_build_pstate_datablock(const Target& i_target, PstateSuperStructure *io_pss) 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; } - + // ------------------------------------------------------------------- // Create s132a_points and filled in by chip_characterization_create() // ------------------------------------------------------------------- @@ -182,13 +152,12 @@ p8_build_pstate_datablock(const Target& i_target, PstateSuperStructure *io_pss) // 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; // pstate0 is turbo - s132a_parms.frequency_step_khz = frequency_step_khz; // ATTR_REFCLK_FREQUENCY/ATTR_DPLL_DIVIDER - - s132a_parms.vdd_load_line_uohm = 570; // hardcoded values to use temporarily per Adrian 4/11 - s132a_parms.vcs_load_line_uohm = 570; // hardcoded values to use temporarily per Adrian 4/11 - s132a_parms.vdd_distribution_uohm = 500; // hardcoded values to use temporarily per Adrian 4/11 - s132a_parms.vcs_distribution_uohm = 800; // hardcoded values to use temporarily per Adrian 4/11 + 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; // -------------------------------------- // Create Chip characterization structure @@ -200,12 +169,6 @@ p8_build_pstate_datablock(const Target& i_target, PstateSuperStructure *io_pss) s132a_characterization.parameters = &s132a_parms; s132a_characterization.points = S132A_POINTS; - // ------------------------------ - // Clear the PstateSuperStructure and install the magic number - // ------------------------------ - memset(io_pss, 0, sizeof(*io_pss)); - (*io_pss).magic = revle64(PSTATE_SUPERSTRUCTURE_MAGIC); - // --------------------------- // Finish the characterization // --------------------------- @@ -224,151 +187,329 @@ p8_build_pstate_datablock(const Target& i_target, PstateSuperStructure *io_pss) return l_rc; } + // ----------------------------------------------------------- + // Clear the PstateSuperStructure and install the magic number + // ----------------------------------------------------------- + memset(io_pss, 0, sizeof(*io_pss)); + (*io_pss).magic = revle64(PSTATE_SUPERSTRUCTURE_MAGIC); + // ------------------------------ // Create the Global Pstate table // ------------------------------ rc = gpst_create(&((*io_pss).gpst), - characterization, - PSTATE_STEPSIZE, - EVRM_DELAY_NS); - - FAPI_DBG("gpst pmin = %d gpst entries = %d", (*io_pss).gpst.pmin, (*io_pss).gpst.entries); - FAPI_DBG("attr_freq_proc_refclock = %d khz", (attr.attr_freq_proc_refclock*1000)); - FAPI_DBG("pstate0_freq = %d frequency_step = %d", s132a_parms.pstate0_frequency_khz, s132a_parms.frequency_step_khz); - FAPI_DBG("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); - + characterization, + PSTATE_STEPSIZE, + EVRM_DELAY_NS); + + FAPI_DBG("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_DBG("GPST pmin = %d entries = %u", (*io_pss).gpst.pmin, (*io_pss).gpst.entries); + FAPI_DBG("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); + if (rc) { int & RETURN_CODE = rc; FAPI_ERR("**** ERROR : Procedure gpst_create() returned %d", rc); FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_GPST_CREATE_ERROR); return l_rc; } - -// jwy // --------------------- -// jwy // calculate safe_pstate -// jwy // --------------------- -// jwy Pstate psafe_pstate; -// jwy rc = freq2pState(&((*io_pss).gpst), (attr.attr_pm_safe_frequency * 1000), &psafe_pstate); -// jwy -// jwy if (rc) { -// jwy fprintf(stderr, " freq2pState() returned %d\n", rc); -// jwy exit(1); -// jwy } -// jwy -// jwy // pstate bounds checking -// jwy Pstate pmax; -// jwy pmax = (*io_pss).gpst.pmin + (*io_pss).gpst.entries - 1; -// jwy -// jwy if (psafe_pstate > pmax) { -// jwy fprintf(stderr, " safe frequency pstate(%d) is greater than max pstate(%d)\n", psafe_pstate, pmax); -// jwy exit(1); -// jwy } -// jwy -// jwy if (psafe_pstate < (*io_pss).gpst.pmin) -// jwy psafe_pstate = (*io_pss).gpst.pmin; -// jwy -// jwy (*io_pss).gpst.psafe = psafe_pstate; -// jwy -// jwy // ----------------------- -// jwy // calculate pvsafe pstate -// jwy // ----------------------- -// jwy Pstate pvsafe_pstate; -// jwy Vid11 pvsafe_vrm11; -// jwy gpst_entry_t entry; -// jwy -// jwy rc = vuv2vrm11((attr.attr_pm_safe_voltage*1000), 1, &pvsafe_vrm11); // assume attr_pm_safe_voltage is in millivolts -// jwy rc = gpst_vdd2pstate(&((*io_pss).gpst), pvsafe_vrm11, &pvsafe_pstate, &entry); -// jwy (*io_pss).gpst.pvsafe = pvsafe_pstate; - - - - // Force optional overrides - (*io_pss).gpst.options.options = revle32(revle32((*io_pss).gpst.options.options) | - PSTATE_NO_INSTALL_LPSA | - PSTATE_NO_INSTALL_RESCLK | - PSTATE_FORCE_INITIAL_PMIN); - // ------------------------------ - // Create the Global Pstate table - // ------------------------------ - rc = lpst_create( &((*io_pss).gpst), &((*io_pss).lpsa), DEAD_ZONE_5MV); - - if (rc) { -// int & RETURN_CODE = rc; + + // ----------------------------- + // Boost the Global Pstate table + // ----------------------------- + l_rc = proc_boost_gpst (io_pss, attr.attr_cpm_turbo_boost_percent); + if (l_rc) + return l_rc; + + // ----------------------------------------------------------------- + // calculate safe_pstate & pvsafe pstate from attr_pm_safe_frequency + // ----------------------------------------------------------------- +// jwy Pstate psafe_pstate; +// jwy rc = freq2pState(&((*io_pss).gpst), (attr.attr_pm_safe_frequency * 1000), &psafe_pstate); +// jwy +// jwy if (rc) { +// jwy fprintf(stderr, " freq2pState() returned %d\n", rc); +// jwy exit(1); +// jwy } +// jwy +// jwy rc = pstate_minmax_chk(&(pss->gpst), &psafe_pstate); +// jwy +// jwy (*io_pss).gpst.psafe = psafe_pstate; +// jwy (*io_pss).gpst.pvsafe = psafe_pstate; + + // ----------------------------- + // Create the Local Pstate table + // ----------------------------- + rc = lpst_create( &((*io_pss).gpst), &((*io_pss).lpsa), DEAD_ZONE_5MV, volt_int_vdd_bias, volt_int_vcs_bias); + + if (rc == -LPST_INVALID_OBJECT) { + int & RETURN_CODE = rc; FAPI_ERR("**** ERROR : Procedure lpst_create() returned %d", rc); - // FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_GPST_CREATE_ERROR); - // return l_rc; - } - - // print global pstate table -// jwy gpst_print(stdout, &(*io_pss).gpst); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_LPST_CREATE_ERROR); + return l_rc; + } + + if (rc == -LPST_GPST_WARNING) { + FAPI_INF("No Local Pstate Generated due Global Pstate Table data" ); + } + + // ----------------------- + // 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[3].Coef, + &(ivrm_mvpd.data.ex[3]) ); + + write_HWtab_bin(&ivrm_parms, + ivrm_mvpd.data.ex[3].Coef, + io_pss); + break; + } + } + + // --------------------------------------- + // Update CPM Range info in Superstructure + // --------------------------------------- + l_rc = proc_upd_cpmrange (io_pss, &attr); + if (l_rc) + return l_rc; + + // ------------------------ + // Force optional overrides + // ------------------------ + (*io_pss).gpst.options.options = revle32(revle32((*io_pss).gpst.options.options) | + PSTATE_NO_INSTALL_RESCLK | + PSTATE_FORCE_INITIAL_PMIN); // Attributes to write // ------------------- // uint32_t ATTR_PM_PSTATE0_FREQUENCY // Binary in Khz return l_rc; -} - +} // end p8_build_pstate_datablock +/// ----------------------------------------------------------------------- /// \brief Get needed attributes /// \param[in] i_target => Chip Target /// \param[inout] attr => pointer to attribute list structure +/// ----------------------------------------------------------------------- -ReturnCode proc_get_attributes(const Target& i_target, AttributeList *attr) { +ReturnCode proc_get_attributes(const Target& i_target, + AttributeList *attr) +{ ReturnCode l_rc; + int i = 0; + + do + { + // -------------------------- + // attributes not yet defined + // -------------------------- + attr->attr_dpll_bias = 0; + attr->attr_undervolting = 0; + + // --------------------------------------------------------------- + // set ATTR_PROC_DPLL_DIVIDER to 4 and do not read attribute value + attr->attr_proc_dpll_divider = 4; + FAPI_INF("ATTR_PROC_DPLL_DIVIDER - set to 4"); + + // ---------------------------- + // 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("%s = 0x%08x %u", #attr_name, attr->attr_assign, attr->attr_assign); + + 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); + // jwy DATABLOCK_GET_ATTR(ATTR_PROC_DPLL_DIVIDER, &i_target, attr_proc_dpll_divider); + 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_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(ATTR_PROC_R_LOADLINE_VDD, NULL, attr_proc_r_loadline_vdd); + DATABLOCK_GET_ATTR(ATTR_PROC_R_LOADLINE_VCS, NULL, attr_proc_r_loadline_vcs); + DATABLOCK_GET_ATTR(ATTR_PROC_R_DISTLOSS_VDD, NULL, attr_proc_r_distloss_vdd); + DATABLOCK_GET_ATTR(ATTR_PROC_R_DISTLOSS_VCS, NULL, attr_proc_r_distloss_vcs); + DATABLOCK_GET_ATTR(ATTR_PROC_VRM_VOFFSET_VDD, NULL, attr_proc_vrm_voffset_vdd); + DATABLOCK_GET_ATTR(ATTR_PROC_VRM_VOFFSET_VCS, NULL, 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]); + } + + // -------------------------------------------------------------- + // do basic attribute value checking and generate error if needed + // -------------------------------------------------------------- + + // jwy FIXME Add this error check once attr_pm_safe_frequency attribute is updated to be uint32 + // jwy if (attr->attr_pm_safe_frequency > attr->attr_boot_freq_mhz) { + // jwy FAPI_ERR("ATTR_PM_SAFE_FREQUENCY (%u) is greater than ATTR_BOOT_FREQ_MHZ (%u)", attr->attr_pm_safe_frequency, attr->attr_boot_freq_mhz); + // jwy FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_LPST_CREATE_ERROR); + // jwy return l_rc; + // jwy } + + // ---------------------------------------------------- + // 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_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_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_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_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_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_DBG("Double Biasing enabled on external and internal VDD"); + } + + 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_DBG("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_DBG("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_DBG("Attribute value was 0 - setting to default value ATTR_PM_SAFE_FREQUENCY = ATTR_BOOT_FREQ_MHZ"); + } + + if (attr->attr_proc_r_loadline_vdd == 0) { + attr->attr_proc_r_loadline_vdd = 570; + FAPI_DBG("Attribute value was 0 - setting to default value ATTR_PROC_R_LOADLINE_VDD = 570"); + } + + if (attr->attr_proc_r_loadline_vcs == 0) { + attr->attr_proc_r_loadline_vcs = 570; + FAPI_DBG("Attribute value was 0 - setting to default value ATTR_PROC_R_LOADLINE_VCS = 570"); + } + + if (attr->attr_proc_r_distloss_vdd == 0) { + attr->attr_proc_r_distloss_vdd = 500; + FAPI_DBG("Attribute value was 0 - setting to default value ATTR_PROC_R_DISTLOSS_VDD = 500"); + } + + if (attr->attr_proc_r_distloss_vcs == 0) { + attr->attr_proc_r_distloss_vcs = 800; + FAPI_DBG("Attribute value was 0 - setting to default value ATTR_PROC_R_DISTLOSS_VCS = 800"); + } + } while (0); - // -------------------------- - // attributes not yet defined - // -------------------------- - attr->attr_dpll_bias = 0; - attr->attr_undervolting = 0; - attr->attr_freq_bias_up = 0; - attr->attr_freq_bias_down = 0; - attr->attr_voltage_ext_bias_up = 0; - attr->attr_voltage_ext_bias_down = 0; - attr->attr_voltage_int_bias_up = 0; - attr->attr_voltage_int_bias_down = 0; - - attr->attr_dpll_bias = 0; - attr->attr_undervolting = 0; - attr->attr_pm_safe_voltage = 925; // assume millivolts until it is defined in attraibute - attr->attr_proc_dpll_divider = 4; - - l_rc = FAPI_ATTR_GET(ATTR_FREQ_PROC_REFCLOCK, NULL, attr->attr_freq_proc_refclock); if (l_rc) return l_rc; -// jwy l_rc = FAPI_ATTR_GET(ATTR_PROC_DPLL_DIVIDER, NULL, attr->attr_proc_dpll_divider); if (l_rc) return l_rc; - l_rc = FAPI_ATTR_GET(ATTR_FREQ_CORE_MAX, NULL, attr->attr_freq_core_max); if (l_rc) return l_rc; - l_rc = FAPI_ATTR_GET(ATTR_PROC_R_LOADLINE, NULL, attr->attr_proc_r_loadline); if (l_rc) return l_rc; - l_rc = FAPI_ATTR_GET(ATTR_PROC_R_DISTLOSS, NULL, attr->attr_proc_r_distloss); if (l_rc) return l_rc; - l_rc = FAPI_ATTR_GET(ATTR_PROC_VRM_VOFFSET, NULL, attr->attr_proc_vrm_voffset); if (l_rc) return l_rc; - - l_rc = FAPI_ATTR_GET(ATTR_PM_SAFE_FREQUENCY, NULL, attr->attr_pm_safe_frequency); if (l_rc) return l_rc; - - l_rc = FAPI_ATTR_GET(ATTR_PM_RESONANT_CLOCK_FULL_CLOCK_SECTOR_BUFFER_FREQUENCY, NULL, attr->attr_pm_resonant_clock_full_clock_sector_buffer_frequency); if (l_rc) return l_rc; - l_rc = FAPI_ATTR_GET(ATTR_PM_RESONANT_CLOCK_LOW_BAND_LOWER_FREQUENCY, NULL, attr->attr_pm_resonant_clock_low_band_lower_frequency); if (l_rc) return l_rc; - l_rc = FAPI_ATTR_GET(ATTR_PM_RESONANT_CLOCK_LOW_BAND_UPPER_FREQUENCY, NULL, attr->attr_pm_resonant_clock_low_band_upper_frequency); if (l_rc) return l_rc; - l_rc = FAPI_ATTR_GET(ATTR_PM_RESONANT_CLOCK_HIGH_BAND_LOWER_FREQUENCY, NULL, attr->attr_pm_resonant_clock_high_band_lower_frequency); if (l_rc) return l_rc; - l_rc = FAPI_ATTR_GET(ATTR_PM_RESONANT_CLOCK_HIGH_BAND_UPPER_FREQUENCY, NULL, attr->attr_pm_resonant_clock_high_band_upper_frequency); if (l_rc) return l_rc; - 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]) { +ReturnCode proc_get_mvpd_data(const Target& i_target, + uint32_t attr_mvpd_data[PV_D][PV_W], + ivrm_mvpd_t *ivrm_mvpd) +{ ReturnCode l_rc; std::vector<fapi::Target> l_exChiplets; - uint8_t l_functional = 0; - uint8_t * l_buffer = reinterpret_cast<uint8_t *>(malloc(512) ); - uint32_t l_bufferSize = 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 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 version_pdm = 0; + uint8_t bucket_id = 0; + uint16_t cal_data[4]; // ----------------------------------------------------------------- // get list of chiplets and loop over each and get #V data from each @@ -393,7 +534,8 @@ ReturnCode proc_get_mvpd_data(const Target& i_target, uint32_t attr_mvpd_data[PV else { if ( l_functional ) { - l_bufferSize = 512; + 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) { @@ -416,9 +558,9 @@ ReturnCode proc_get_mvpd_data(const Target& i_target, uint32_t attr_mvpd_data[PV } // check buffer size - if (l_bufferSize < MVPD_BUFFER_SIZE) { - FAPI_ERR("**** ERROR : Worng size buffer returned from fapiGetMvpdField => %d", l_bufferSize ); - FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_MVPD_BUFFER_SIZE_ERROR); + if (l_bufferSize < PDV_BUFFER_SIZE) { + FAPI_ERR("**** ERROR : Wrong size buffer returned from fapiGetMvpdField for #V => %d", l_bufferSize ); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PDV_BUFFER_SIZE_ERROR); return l_rc; } @@ -427,15 +569,22 @@ ReturnCode proc_get_mvpd_data(const Target& i_target, uint32_t attr_mvpd_data[PV // 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) ) )) - l_buffer++; + + // use copy of allocated buffer pointer to increment through buffer + l_buffer_inc = l_buffer; + + bucket_id = *l_buffer_inc; + l_buffer_inc++; + + FAPI_DBG("#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); - FAPI_DBG("%04X %-6d", chiplet_mvpd_data[i][ii], chiplet_mvpd_data[i][ii]); + chiplet_mvpd_data[i][ii] = (uint32_t) UINT16_GET(l_buffer_inc); + FAPI_DBG("#V data = 0x%04X %-6d", chiplet_mvpd_data[i][ii], chiplet_mvpd_data[i][ii]); // increment to next MVPD value in buffer - l_buffer+= 2; + l_buffer_inc+= 2; } } @@ -475,16 +624,249 @@ ReturnCode proc_get_mvpd_data(const Target& i_target, uint32_t attr_mvpd_data[PV attr_mvpd_data[i][4] = chiplet_mvpd_data[i][4]; } } + + // -------------------------------------------- + // Process #M Data + // -------------------------------------------- + + // 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_ERR("**** ERROR : Unexpected error encountered in fapiGetMvpdField"); + return l_rc; + } + + // 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 ); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_PDM_BUFFER_SIZE_ERROR); + return l_rc; + } + + // 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 + version_pdm = *l_buffer_pdm_inc; + ivrm_mvpd->header.version = version_pdm ; + l_buffer_pdm_inc++; + + // loop over 13 entries of #M data with 4 measurements per entry + FAPI_DBG("#M chiplet = %u version = %u", l_chipNum, version_pdm); + + for (i=0; i<13; i++) { + + for (ii=0; ii<4; ii++) { + cal_data[ii] = UINT16_GET(l_buffer_pdm_inc); + 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_DBG("#M data = %5u %5u %5u %5u", cal_data[0], cal_data[1], cal_data[2], cal_data[3]); + } + + // set number of samples to 13 + ivrm_mvpd->data.ex[j].point_valid = 13; + } // end if l_functional else { // Not Functional so skip it } } } // end for loop + free (l_buffer); + free (l_buffer_pdm); + return l_rc; } // end proc_get_mvpd_data +/// --------------------------------------------------------------------------- +/// \brief Check and process #V bias attributes for external and internal +/// \param[in] attr_mvpd_data => 5x5 array to hold the #V data +/// \param[in] *attr => pointer to attribute list structure +/// \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_DBG("BIAS freq = %f", freq_bias); + FAPI_DBG("BIAS vdd ext = %f vcs ext = %f", volt_ext_vdd_bias, volt_ext_vcs_bias); + FAPI_DBG("BIAS vdd int = %f vcs int = %f", *volt_int_vdd_bias, *volt_int_vcs_bias); + + return l_rc; +} // end proc_get_extint_bias + + +/// ------------------------------------------------------------ +/// \brief Update CPM Range table +/// \param[inout] *pss => pointer to pstate superstructure +/// \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_DBG("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); + 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_DBG("CPM point freq_khz = %u pstate = %d",freq_khz, pstate); + } + + if (rc) break; + + // convert pMax attribute to Khz and then convert to pstate value + freq_khz = attr->attr_cpm_inflection_points[9] * revle32(pss->gpst.frequency_step_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_DBG("CPM pMax freq_khz = %u pstate = %d",freq_khz, pstate); + } while (0); + + // ------------------------------------------------------ + // check error code from freq2pState or pstate_minmax_chk + // ------------------------------------------------------ + if (rc) { + int & RETURN_CODE = rc; + + if (rc == -PSTATE_LT_PSTATE_MIN || rc == -PSTATE_LT_PSTATE_MIN) { + 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 (max pstate = %d computed 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 + + +/// ------------------------------------------------------------------- +/// \brief Boost max frequency in pstate table based on boost attribute +/// \param[inout] *pss => pointer to pstate superstructure +/// \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; + + // 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 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); + + // if boosted frequency is <= turbo frequency, then no boost is to be done + if (boosted_freq_khz <= pstate0_frequency_khz) + return l_rc; + + // 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) { + return l_rc; + } + else { + gpsi_max = pss->gpst.entries - 1; + entry.value = revle64(pss->gpst.pstate[gpsi_max].value); + + FAPI_DBG("Boosting Pstate Table : %% = %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); + } + + pss->gpst.entries += pstate_diff; + + } + + return l_rc; +} // end proc_boost_gpst + + } //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 e883fc819..94a46f059 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 @@ -20,7 +20,7 @@ /* Origin: 30 */ /* */ /* IBM_PROLOG_END_TAG */ -// $Id: p8_build_pstate_datablock.H,v 1.7 2013/05/03 15:57:32 jimyac Exp $ +// $Id: p8_build_pstate_datablock.H,v 1.9 2013/09/17 16:43:44 jimyac Exp $ #ifndef _P8_BUILD_PSTATE_DATABLOCK_H_ #define _P8_BUILD_PSTATE_DATABLOCK_H_ @@ -44,9 +44,12 @@ fapi::ReturnCode p8_build_pstate_datablock(const fapi::Target& i_target, PstateS #define S132A_POINTS 3 #define PSTATE_STEPSIZE 1 -#define EVRM_DELAY_NS 100 -#define DEAD_ZONE_5MV 20 -#define MVPD_BUFFER_SIZE 51 +#define EVRM_DELAY_NS 100 +#define DEAD_ZONE_5MV 20 +#define PDV_BUFFER_SIZE 51 +#define PDM_BUFFER_SIZE 105 +#define BIAS_PCT_UNIT 0.005 +#define BOOST_PCT_UNIT 0.001 // #V 2 dimensional array values (5x5) - 5 operating point and 5 values per operating point #define PV_D 5 @@ -55,18 +58,35 @@ fapi::ReturnCode p8_build_pstate_datablock(const fapi::Target& i_target, PstateS // order of operating points from slow to fast in #V // 1=pwrsave 0=nominal 2=turbo const uint8_t pv_op_order[S132A_POINTS] = {1, 0, 2}; +#define PV_OP_ORDER {1, 0, 2} typedef struct { - uint32_t attr_freq_core_max; // = 0; // MHz - uint32_t attr_proc_r_loadline; // = 0; // Impedance (binary in microOhms) - uint32_t attr_proc_r_distloss; // = 0; // Impedance (binary in microOhms) - uint32_t attr_proc_vrm_voffset; // = 0; // Offset voltage (binary in microvolts) - - uint32_t attr_freq_proc_refclock; // = 133 ; // Mhz + uint32_t attr_freq_core_max; + uint32_t attr_proc_r_loadline_vdd; + uint32_t attr_proc_r_loadline_vcs; + uint32_t attr_proc_r_distloss_vdd; + uint32_t attr_proc_r_distloss_vcs; + uint32_t attr_proc_vrm_voffset_vdd; + uint32_t attr_proc_vrm_voffset_vcs; + uint32_t attr_voltage_ext_vdd_bias_up; + uint32_t attr_voltage_ext_vcs_bias_up; + uint32_t attr_voltage_ext_vdd_bias_down; + uint32_t attr_voltage_ext_vcs_bias_down; + uint32_t attr_voltage_int_vdd_bias_up; + uint32_t attr_voltage_int_vcs_bias_up; + uint32_t attr_voltage_int_vdd_bias_down; + uint32_t attr_voltage_int_vcs_bias_down ; + + uint32_t attr_proc_r_loadline; // = 0; // Impedance (binary in microOhms) + uint32_t attr_proc_r_distloss; // = 0; // Impedance (binary in microOhms) + uint32_t attr_proc_vrm_voffset; // = 0; // Offset voltage (binary in microvolts) + + uint32_t attr_freq_proc_refclock; // = 133333 ; // Khz uint32_t attr_proc_dpll_divider; // = 4; - - uint32_t attr_freq_bias_up; // = 0; - uint32_t attr_freq_bias_down; // = 0; + uint32_t attr_cpm_turbo_boost_percent; // binary in 0.1 percent steps + uint32_t attr_cpm_inflection_points[16]; + uint32_t attr_freq_ext_bias_up; // = 0; + uint32_t attr_freq_ext_bias_down; // = 0; uint32_t attr_voltage_ext_bias_up; // = 0; uint32_t attr_voltage_ext_bias_down; // = 0; uint32_t attr_voltage_int_bias_up; // = 0; @@ -74,9 +94,9 @@ typedef struct { uint32_t attr_dpll_bias; uint32_t attr_undervolting; - uint32_t attr_pm_safe_voltage; - uint8_t attr_pm_safe_frequency; // = 0; // pstate value -128 thru 127 *** FIXME - comes in as unsigned, how to I make signed??? - + uint8_t attr_pm_safe_frequency; + uint32_t attr_boot_freq_mhz; + uint32_t attr_pm_resonant_clock_full_clock_sector_buffer_frequency; // = 0; // Mhz uint32_t attr_pm_resonant_clock_low_band_lower_frequency; // = 0; // Mhz uint32_t attr_pm_resonant_clock_low_band_upper_frequency; // = 0; // Mhz 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 04d3585c8..4acf8267d 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 @@ -20,16 +20,21 @@ <!-- Origin: 30 --> <!-- --> <!-- IBM_PROLOG_END_TAG --> -<!-- $Id: p8_build_pstate_datablock_errors.xml,v 1.5 2013/05/03 16:10:11 jimyac Exp $ --> +<!-- $Id: p8_build_pstate_datablock_errors.xml,v 1.7 2013/09/17 16:37:19 jimyac Exp $ --> <!-- Error definitions for p8_build_pstate_datablock procedure --> <hwpErrors> <!-- *********************************************************************** --> <hwpError> - <rc>RC_PROCPM_PSTATE_DATABLOCK_MVPD_BUFFER_SIZE_ERROR</rc> - <description>MVPD Buffer returned is wrong size</description> + <rc>RC_PROCPM_PSTATE_DATABLOCK_PDV_BUFFER_SIZE_ERROR</rc> + <description>#V Buffer returned is wrong size</description> </hwpError> <!-- *********************************************************************** --> <hwpError> + <rc>RC_PROCPM_PSTATE_DATABLOCK_PDM_BUFFER_SIZE_ERROR</rc> + <description>#M Buffer returned is wrong size</description> + </hwpError> + <!-- *********************************************************************** --> + <hwpError> <rc>RC_PROCPM_PSTATE_MVPD_CHIPLET_VOLTAGE_NOT_EQUAL</rc> <description>MVPD Bucket Frequency was not equal per chiplet</description> </hwpError> @@ -60,4 +65,28 @@ <description>Procedure gpst_create() returned an error</description> <ffdc>RETURN_CODE</ffdc> </hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROCPM_PSTATE_DATABLOCK_LPST_CREATE_ERROR</rc> + <description>Procedure lpst_create() returned an error</description> + <ffdc>RETURN_CODE</ffdc> + </hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROCPM_PSTATE_DATABLOCK_PSTATE_MINMAX_BOUNDS_ERROR</rc> + <description>freq2pState returned error - computed pstate for freq is out of bounds of MAX/MIN possible</description> + <ffdc>RETURN_CODE</ffdc> + </hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROCPM_PSTATE_DATABLOCK_PSTATE_GT_GPSTPMAX_ERROR</rc> + <description>pstate_minmax_chk returned error - Computed pstate is greater than max pstate in gpst</description> + <ffdc>RETURN_CODE</ffdc> + </hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROCPM_PSTATE_DATABLOCK_ERROR</rc> + <description>Bad Return code</description> + <ffdc>RETURN_CODE</ffdc> + </hwpError> </hwpErrors> diff --git a/src/usr/hwpf/hwp/pstates/pstates/p8_ivrm.H b/src/usr/hwpf/hwp/pstates/pstates/p8_ivrm.H new file mode 100644 index 000000000..3ab7f0fc9 --- /dev/null +++ b/src/usr/hwpf/hwp/pstates/pstates/p8_ivrm.H @@ -0,0 +1,110 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hwpf/hwp/pstates/pstates/p8_ivrm.H $ */ +/* */ +/* IBM CONFIDENTIAL */ +/* */ +/* COPYRIGHT International Business Machines Corp. 2013 */ +/* */ +/* p1 */ +/* */ +/* Object Code Only (OCO) source materials */ +/* Licensed Internal Code Source Materials */ +/* IBM HostBoot Licensed Internal Code */ +/* */ +/* The source code for this program is not published or otherwise */ +/* divested of its trade secrets, irrespective of what has been */ +/* deposited with the U.S. Copyright Office. */ +/* */ +/* Origin: 30 */ +/* */ +/* IBM_PROLOG_END_TAG */ +// $Id: p8_ivrm.H,v 1.1 2013/08/13 17:13:00 jimyac Exp $ +// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/ipl/fapi/p8_ivrm.H,v $ +//------------------------------------------------------------------------------ +// *! (C) Copyright International Business Machines Corp. 2011 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//------------------------------------------------------------------------------ +// *! OWNER NAME: Greg Still Email: stillgs@us.ibm.com +// *! +// *! General Description: +// *! #M IVRM Vital Product Data Structure +//------------------------------------------------------------------------------ +// +// +// +// 4 x 2B = 8B per measurement +typedef struct IVRM_MEASUREMENT { + uint16_t gate_voltage; // V1: mV, V2: uV + uint16_t drain_voltage; // V1: mV, V2: uV + uint16_t source_voltage; // V1: mV, V2: uV + uint16_t drain_current; // V1: mA, V2: uA +} ivrm_measurement_t; + +// 8B x 32 measurements = 256B cal data +#define IVRM_CAL_POINTS 32 +typedef struct IVRM_CAL_DATA { + uint32_t point_valid; // bit vector indicating valid points + double Coef[4]; + ivrm_measurement_t point[IVRM_CAL_POINTS]; +} ivrm_cal_data_t; + +#define MURANO 1 + +#ifdef MURANO +#define CHIPLETS 6 +#elif VENICE +#define CHIPLETS 12 +#endif + +// Murano: 256B x 6 = 1036B + 2 (temp) = 1038B +// Venice: 256B x 12 = 2072B + 2 (temp) = 2074B + +typedef struct IVRM_EX_CAL_DATA +{ + uint16_t temp; // binary in degrees C + uint16_t ex_valid; // bit vector of valid chiplets, left justified + ivrm_cal_data_t ex[CHIPLETS]; +} ivrm_ex_cal_data_t; + +// 4 byte header +typedef struct IVRM_MVPD_HEADER +{ + char name[2]; // Two character ID + uint8_t length; // Version 1: milli units; Version 2: micro units + uint8_t version; +} ivrm_mvpd_header_t; + + +typedef struct IVRM_MVPD +{ + ivrm_mvpd_header_t header; + ivrm_ex_cal_data_t data; +} ivrm_mvpd_t; + +// Chiplet numbering to indexing needs translation if VPD is held "packed" +// (eg 0:5 for Murano; 0:11 for Venice) +// +// Murano translation +// Index 0 <> EX 4 +// Index 1 <> EX 5 +// Index 2 <> EX 6 +// Index 3 <> EX C (12) +// Index 4 <> EX D (13) +// Index 5 <> EX E (14) +// +// Venice translation +// Index 0 <> EX 1 +// Index 1 <> EX 2 +// Index 2 <> EX 3 +// Index 3 <> EX 4 +// Index 4 <> EX 5 +// Index 5 <> EX 6 +// Index 6 <> EX 9 +// Index 7 <> EX A (10) +// Index 8 <> EX B (11) +// Index 9 <> EX C (12) +// Index 10 <> EX D (13) +// Index 11 <> EX E (14) diff --git a/src/usr/hwpf/hwp/pstates/pstates/pstate_tables.c b/src/usr/hwpf/hwp/pstates/pstates/pstate_tables.c index 5212b1a76..a299e5fb7 100755 --- a/src/usr/hwpf/hwp/pstates/pstates/pstate_tables.c +++ b/src/usr/hwpf/hwp/pstates/pstates/pstate_tables.c @@ -20,7 +20,7 @@ /* Origin: 30 */ /* */ /* IBM_PROLOG_END_TAG */ -// $Id: pstate_tables.c,v 1.8 2013/06/12 20:02:07 mjjones Exp $ +// $Id: pstate_tables.c,v 1.10 2013/09/17 16:36:39 jimyac Exp $ /// \file pstate_tables.c /// \brief This file contains code used to generate Pstate tables from real or @@ -30,12 +30,12 @@ /// 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) \ ({ \ typeof (X) __x = (X); \ @@ -209,7 +209,7 @@ chip_characterization_create(ChipCharacterization *characterization, ops[gpst_points].idd_ma = vpd[i].idd_500ma * 500; 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 @@ -268,7 +268,9 @@ chip_characterization_create(ChipCharacterization *characterization, // // \retval -GPST_INVALID_ARGUMENT Either argument was invalid in some way. -#define NEST_FREQUENCY_KHZ 2400000 +// jwy if we use this proc in future, do not use this value for nest freq +// instead, use the value of attribute ATTR_FREQ_PB +#define NEST_FREQ_KHZ 2400000 int gpst_stepping_setup(GlobalPstateTable* gpst, @@ -293,13 +295,15 @@ gpst_stepping_setup(GlobalPstateTable* gpst, // This is the frequency of the VRM stepper 'tick'. The base time // source for VRM stepping is therefore nest clock / 8. - cycles = (((NEST_FREQUENCY_KHZ / 1000) * vrm_delay_ns) / 1000) / + cycles = (((NEST_FREQ_KHZ / 1000) * vrm_delay_ns) / 1000) / (1 << LOG2_VRM_STEPDELAY_DIVIDER); // Normalize the exponential encoding sigbits = 32 - cntlz32(cycles); - stepdelay_range = (sigbits - VRM_STEPDELAY_RANGE_BITS); +// jwy stepdelay_range = MAX(0, sigbits - VRM_STEPDELAY_RANGE_BITS); + + stepdelay_range = (sigbits - VRM_STEPDELAY_RANGE_BITS); if (stepdelay_range < 0) { @@ -364,12 +368,14 @@ gpst_entry_create(gpst_entry_t *entry, OperatingPoint *op) 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_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); @@ -510,6 +516,8 @@ gpst_create(GlobalPstateTable *gpst, // Set the Pmin Pstate + for (i = 0; i < points; i++) + entry = 0; if (gpst_entry_create(&(gpst->pstate[entry]), &(ops[0]))) { rc = -GPST_INVALID_ENTRY; @@ -576,52 +584,101 @@ gpst_create(GlobalPstateTable *gpst, } +/// Create a local Pstate table +/// +/// \param gpst A pointer to a GlobalPstateTable structure for lookup. +/// +/// \param lpsa Apointer 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 +/// +/// \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 +/// 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) +lpst_create(const GlobalPstateTable *gpst, + LocalPstateArray *lpsa, + const uint8_t dead_zone_5mv, + double volt_int_vdd_bias, + double volt_int_vcs_bias) { - int rc = 0; + int rc = 0; int i,j; gpst_entry_t entry; uint32_t turbo_uv; + uint32_t gpst_uv; uint32_t v_uv; uint32_t vdd_uv; - uint8_t v_ivid; + uint8_t v_ivid; + uint8_t gpst_ivid; + int 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_pmin; + Pstate lpst_pstate; + 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 inc_step; + uint8_t dec_step; do { // Basic pointer checks - if (lpsa == 0) { + if ((gpst == 0) || (lpsa == 0)) { 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 = vrm112vuv(entry.fields.evid_vdd, &turbo_uv); + rc = vrm112vuv(entry.fields.evid_vdd, &turbo_uv); if (rc) break; + + 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); - vrm112vuv(entry.fields.evid_vdd, &v_uv); + for (i = gpst->entries - 1 ; i >= 0; i--) { + entry.value = revle64(gpst->pstate[i].value); + rc = vrm112vuv(entry.fields.evid_vdd, &v_uv); if (rc) break; + v_uv = (uint32_t) (v_uv * volt_int_vdd_bias); - if (lpst_max_uv >= v_uv) - break; + if (lpst_max_uv >= v_uv) { + lpst_max_found = 1; + lpst_max_pstate = gpst_pmax(gpst) - (gpst->entries - i - 1); + break; + } + } + + 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; } - - lpst_entries = i + 1; - lpst_pmin = 0 - lpst_entries + 1; -// jwy printf("turbo_uv = %d lpst_max_uv = %d entries = %d lpst_pmin = %d\n", turbo_uv, lpst_max_uv, lpst_entries, lpst_pmin); + lpst_entries = gpst->entries; + lpst_pmin = gpst->pmin; + +// jwy printf("turbo_uv = %d lpst_max_uv = %d entries = %d lpst_pmin = %d lpst_max_pstate = %d i = %d\n", turbo_uv, lpst_max_uv, lpst_entries, lpst_pmin, lpst_max_pstate, i); // ---------------------------------------------------------------------------- // now loop over gpst from 0 to lpst_entries and fill in lpst from data in gpst @@ -631,18 +688,23 @@ lpst_create(const GlobalPstateTable *gpst, LocalPstateArray *lpsa, const uint8_t lpst_entries_div4 = lpst_entries/4; if ( lpst_entries % 4 != 0) lpst_entries_div4++; - + + // current lpst pstate value as table is created + lpst_pstate = gpst_pmin(gpst); + for (i = 0 ; i < lpst_entries_div4; i++) { entry.value = revle64(gpst->pstate[gpst_index].value); // compute ivid_vdd - rc = vrm112vuv(entry.fields.evid_vdd, &vdd_uv); - rc = vuv2ivid(vdd_uv, ROUND_VOLTAGE_DOWN, &v_ivid); + rc = vrm112vuv(entry.fields.evid_vdd, &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 = vrm112vuv(entry.fields.evid_vcs, &v_uv); - rc = vuv2ivid(v_uv, ROUND_VOLTAGE_DOWN, &v_ivid); + rc = vrm112vuv(entry.fields.evid_vcs, &v_uv); if (rc) break; + 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; // -------------------------------------------------------------- @@ -654,14 +716,37 @@ lpst_create(const GlobalPstateTable *gpst, LocalPstateArray *lpsa, const uint8_t 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 = vrm112vuv(entry.fields.evid_vdd, &vdd_uv); - rc = vuv2ivid(vdd_uv, ROUND_VOLTAGE_DOWN, &v_ivid); + rc = vrm112vuv(entry.fields.evid_vdd, &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; 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; + + // if in regulation, return an error + if (lpst_pstate <= lpst_max_pstate) { + rc = -LPST_INCR_CLIP_ERROR ; + break; + } + + // if not in regulation, return a warning + if (lpst_pstate > lpst_max_pstate) { +// rc = 2; +// break; + } + } + } + if (rc) break; lpsa->pstate[i].fields.ps1_vid_incr = vid_incr[0]; lpsa->pstate[i].fields.ps2_vid_incr = vid_incr[1]; @@ -682,18 +767,78 @@ lpst_create(const GlobalPstateTable *gpst, LocalPstateArray *lpsa, const uint8_t // 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 + 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; - pwrratio = (uint8_t)((pwrratio_f*64) + 0.5); + + if (pwrratio_f >= 1.0) + pwrratio = 63; + 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; + + // ------------------------------------ + // 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 + + // 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; +// jwy printf("%d %d %d\n", lpst_pstate,j, steps_above_curr); + entry.value = revle64(gpst->pstate[lpst_pstate - gpst_pmin(gpst) + j].value); + rc = vrm112vuv(entry.fields.evid_vdd, &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; + } + + if (rc) break; + + // clip inc_step + if (inc_step > 7) + inc_step = 7; + + + lpsa->pstate[i].fields.inc_step = inc_step; +// jwy lpsa->pstate[i].fields.inc_step = 0; // FIXME - temporary patch! - // ??? what should these be ??? set to 1 for now - lpsa->pstate[i].fields.inc_step = 1; - lpsa->pstate[i].fields.dec_step = 1; + // 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; +// jwy printf("%d %d %d\n", lpst_pstate,j, steps_below_curr); + entry.value = revle64(gpst->pstate[lpst_pstate - gpst_pmin(gpst) - j].value); + rc = vrm112vuv(entry.fields.evid_vdd, &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; + } + + if (rc) break; + + // clip dec_step + if (dec_step > 7) + dec_step = 7; + + lpsa->pstate[i].fields.dec_step = dec_step; +// jwy lpsa->pstate[i].fields.dec_step = 0; // FIXME - temporary patch! // jwy printf (" %d %X %X %f %d %d %d %d\n", i, (uint32_t)lpsa->pstate[i].fields.ivid_vdd, (uint32_t)lpsa->pstate[i].fields.ivid_vcs, pwrratio_f, pwrratio, vid_incr[0], vid_incr[1], vid_incr[2]); @@ -703,14 +848,413 @@ lpst_create(const GlobalPstateTable *gpst, LocalPstateArray *lpsa, const uint8_t gpst_index++; if (gpst_index > lpst_entries) break; + + // point to next lpst pstate + lpst_pstate++; } // set these fields in lpst structure - lpsa->pmin = lpst_pmin; - lpsa->entries = lpst_entries; - + 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 +} // 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) +{ + int 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; + + 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; +// jwy printf(" Vds_region[%x]: begin - %02llX, end - %02llX\n", i, beg_offset, 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; + } +} + +// 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) +{ + int s; + int i; + int idx; +// uint8_t pfetstr = 17; + + i = i_ivrm_parms->vin_table_setsperrow; + for (i = 0; i < i_ivrm_parms->vds_region_entries; i++) + { + for (s = 0; s < i_ivrm_parms->vin_table_setsperrow; s++) { + idx = (i*4) + s; + pss->lpsa.vdsvin[idx].fields.pfet0 = i_ivrm_parms->forced_pfetstr_value; + pss->lpsa.vdsvin[idx].fields.pfet1 = i_ivrm_parms->forced_pfetstr_value; + pss->lpsa.vdsvin[idx].fields.pfet2 = i_ivrm_parms->forced_pfetstr_value; + pss->lpsa.vdsvin[idx].fields.pfet3 = i_ivrm_parms->forced_pfetstr_value; + pss->lpsa.vdsvin[idx].fields.pfet4 = i_ivrm_parms->forced_pfetstr_value; + pss->lpsa.vdsvin[idx].fields.pfet5 = i_ivrm_parms->forced_pfetstr_value; + pss->lpsa.vdsvin[idx].fields.pfet6 = i_ivrm_parms->forced_pfetstr_value; + pss->lpsa.vdsvin[idx].fields.pfet7 = i_ivrm_parms->forced_pfetstr_value; + +// jwy pss->lpsa.vdsvin[idx].fields.pfet0 = pfetstr; pfetstr++; if (pfetstr%32 == 0) pfetstr = 17; +// jwy pss->lpsa.vdsvin[idx].fields.pfet1 = pfetstr; pfetstr++; if (pfetstr%32 == 0) pfetstr = 17; +// jwy pss->lpsa.vdsvin[idx].fields.pfet2 = pfetstr; pfetstr++; if (pfetstr%32 == 0) pfetstr = 17; +// jwy pss->lpsa.vdsvin[idx].fields.pfet3 = pfetstr; pfetstr++; if (pfetstr%32 == 0) pfetstr = 17; +// jwy pss->lpsa.vdsvin[idx].fields.pfet4 = pfetstr; pfetstr++; if (pfetstr%32 == 0) pfetstr = 17; +// jwy pss->lpsa.vdsvin[idx].fields.pfet5 = pfetstr; pfetstr++; if (pfetstr%32 == 0) pfetstr = 17; +// jwy pss->lpsa.vdsvin[idx].fields.pfet6 = pfetstr; pfetstr++; if (pfetstr%32 == 0) pfetstr = 17; +// jwy pss->lpsa.vdsvin[idx].fields.pfet7 = pfetstr; pfetstr++; if (pfetstr%32 == 0) pfetstr = 17; + +// jwy printf(" Vin[%d]{%d,%d}: %016llX\n", idx, i, s, pss->lpsa.vdsvin[idx].value); + + // Byte reverse the entry into the image. + pss->lpsa.vdsvin[idx].value = revle64(pss->lpsa.vdsvin[idx].value); + } + } +} + +#undef abs +#define abs(x) (((x)<0.0)?(-(x)):(x)) + +void simeq(int n, double A[], double Y[], double X[]) +{ + +/* PURPOSE : SOLVE THE LINEAR SYSTEM OF EQUATIONS WITH REAL */ +/* COEFFICIENTS [A] * |X| = |Y| */ +/* */ +/* INPUT : THE NUMBER OF EQUATIONS n */ +/* THE REAL MATRIX A should be A[i][j] but A[i*n+j] */ +/* THE REAL VECTOR Y */ +/* OUTPUT : THE REAL VECTOR X */ +/* */ +/* METHOD : GAUSS-JORDAN ELIMINATION USING MAXIMUM ELEMENT */ +/* FOR PIVOT. */ +/* */ +/* USAGE : simeq(n,A,Y,X); */ +/* */ +/* */ +/* WRITTEN BY : JON SQUIRE , 28 MAY 1983 */ +/* ORIGINAL DEC 1959 for IBM 650, TRANSLATED TO OTHER LANGUAGES */ +/* e.g. FORTRAN converted to Ada converted to C */ + + double *B; /* [n][n+1] WORKING MATRIX */ + int *ROW; /* ROW INTERCHANGE INDICES */ + int HOLD , I_PIVOT; /* PIVOT INDICES */ + double PIVOT; /* PIVOT ELEMENT VALUE */ + double ABS_PIVOT; + int i,j,k,m; + + B = (double *)calloc((n+1)*(n+1), sizeof(double)); + ROW = (int *)calloc(n, sizeof(int)); + m = n+1; + + /* BUILD WORKING DATA STRUCTURE */ + for(i=0; i<n; i++){ + for(j=0; j<n; j++){ + B[i*m+j] = A[i*n+j]; + } + B[i*m+n] = Y[i]; + } + /* SET UP ROW INTERCHANGE VECTORS */ + for(k=0; k<n; k++){ + ROW[k] = k; + } + + /* BEGIN MAIN REDUCTION LOOP */ + for(k=0; k<n; k++){ + + /* FIND LARGEST ELEMENT FOR PIVOT */ + PIVOT = B[ROW[k]*m+k]; + ABS_PIVOT = abs(PIVOT); + I_PIVOT = k; + for(i=k; i<n; i++){ + if( abs(B[ROW[i]*m+k]) > ABS_PIVOT){ + I_PIVOT = i; + PIVOT = B[ROW[i]*m+k]; + ABS_PIVOT = abs ( PIVOT ); + } + } + + /* HAVE PIVOT, INTERCHANGE ROW POINTERS */ + HOLD = ROW[k]; + ROW[k] = ROW[I_PIVOT]; + ROW[I_PIVOT] = HOLD; + + /* CHECK FOR NEAR SINGULAR */ + if( ABS_PIVOT < 1.0E-10 ){ + for(j=k+1; j<n+1; j++){ + B[ROW[k]*m+j] = 0.0; + } +// jwy printf("redundant row (singular) %d \n", ROW[k]); + } /* singular, delete row */ + else{ + + /* REDUCE ABOUT PIVOT */ + for(j=k+1; j<n+1; j++){ + B[ROW[k]*m+j] = B[ROW[k]*m+j] / B[ROW[k]*m+k]; + } + + /* INNER REDUCTION LOOP */ + for(i=0; i<n; i++){ + if( i != k){ + for(j=k+1; j<n+1; j++){ + B[ROW[i]*m+j] = B[ROW[i]*m+j] - B[ROW[i]*m+k] * B[ROW[k]*m+j]; + } + } + } + } + /* FINISHED INNER REDUCTION */ + } + + /* END OF MAIN REDUCTION LOOP */ + /* BUILD X FOR RETURN, UNSCRAMBLING ROWS */ + for(i=0; i<n; i++){ + X[i] = B[ROW[i]*m+n]; + } + free(B); + free(ROW); +} /* end simeq */ + + +void fit_file(int n, uint8_t version, double C[], ivrm_cal_data_t* cal_data) +{ + int i, j, k; + int points; + double y; + double Vd, Vs; +// jwy double Vg; + double x[30]; /* at least 2n */ + 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; + Vd_v1[1] = 831; Vs_v1[1] = 1033; + Vd_v1[2] = 787; Vs_v1[2] = 1033; + Vd_v1[3] = 718; Vs_v1[3] = 1033; + Vd_v1[4] = 962; Vs_v1[4] = 1179; + Vd_v1[5] = 918; Vs_v1[5] = 1179; + Vd_v1[6] = 850; Vs_v1[6] = 1179; + Vd_v1[7] = 750; Vs_v1[7] = 1179; + Vd_v1[8] = 1093; Vs_v1[8] = 1325; + Vd_v1[9] = 1050; Vs_v1[9] = 1325; + 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; + + for(i=0; i<n; i++) + { + for(j=0; j<n; j++) + { + A[i*n+j] = 0.0; + } + 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]; +// jwy Vg = (double)cal_data->point[k].gate_voltage/1000; // uV + y = ((double)cal_data->point[k].drain_current)/1000; // uA + } + else if (version == 1 || version == 2){ + Vd = (double)cal_data->point[k].drain_voltage; // mV + Vs = (double)cal_data->point[k].source_voltage; // mV +// jwy Vg = (double)cal_data->point[k].gate_voltage/1000; // uV + 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 +// jwy Vg = (double)cal_data->point[k].gate_voltage; // mV + y = ((double)cal_data->point[k].drain_current)/1000; // uA + } + +// jwy printf (" %f %f %f %f\n", Vd, Vs, Vg, y ); + + 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 + +// jwy if (Vg>20) { printf("ERROR: gate voltage > 20mV: current=%lf, Vd=%lf, Vs=%lf, Vg=%lf\n", y, Vd, Vs, Vg); } + + for(i=0; i<n; i++) { + for(j=0; j<n; j++) { + A[i*n+j] = A[i*n+j] + x[i]*x[j]; + } + Y[i] = Y[i] + y*x[i]; + } + } + + simeq(n, A, Y, C); + +// jwy for(i=0; i<n; i++) printf("C[%d]=%g \n", i, C[i]); +} /* end fit_file */ + +// jwy void dec2bin(int h, int n) { +// jwy int i; +// jwy char b[12]; +// jwy if (n>12) { n = 12; } +// jwy for( i = n-1; i >= 0; i--) { +// jwy if( (1 << i) & h) { +// jwy b[n - i] = '1'; +// jwy printf("%c",b[n-i]); +// jwy } else { +// jwy b[n - i] = '0'; +// jwy printf("%c",b[n-i]); +// jwy } +// jwy } +// jwy +// jwy b[n] = 0; // ascii terminating character +// jwy } + + +void write_HWtab_bin(ivrm_parm_data_t* i_ivrm_parms, + double C[], + PstateSuperStructure* pss) +{ + int i, j; + double VIN_MIN; + double VDS_MIN; + double Vin[40]; /* at least 2n */ + double Vds[40]; + int NUM_VIN; + int NUM_VDS; + double LSB_CURRENT; + double TEMP_UPLIFT; + double Ical[40][40]; + double Iratio[40][40]; + uint8_t Iratio_int[40][40]; + int 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 = 800; + VDS_MIN = 100; + LSB_CURRENT = 4.1; + 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); + Vds[i] = temp*6.25 ; + } + +// jwy printf("\t"); +// jwy for(i=0; i<NUM_VDS; i++) { printf("%lf\t", Vds[i]); } +// jwy printf("\n"); + + for(i=0; i<NUM_VIN; i++) { +// jwy printf("%lf\t", Vin[i]); + + for (j=0; j<NUM_VDS; j++) { + 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]; + + temp = (int) (Iratio[i][j]+1/16>3.875 ? 3.875 : Iratio[i][j]+1/16); +// jwy dec2bin(temp, 2); + 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 + //printf("."); + + temp = (int) ((Iratio[i][j] - temp)*8 + 0.5); +// jwy dec2bin(temp, 3); + 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; +// printf(" %u",ratio_val); +// jwy printf("\t"); + } else { + Iratio[i][j] = 0; + Iratio_int[i][j] = 0; +// jwy printf("0*\t"); + } + //printf("%lf\t", Iratio[i][j]); + } +// jwy printf("\n"); + } + +// jwy for (i=0; i<NUM_VDS; i++) { +// jwy +// jwy for(j=0; j<NUM_VIN; j++) { +// jwy printf("%u ",Iratio_int[i][j]); +// jwy } +// jwy printf("\n"); +// jwy } + + + // 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; + 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]; + pss->lpsa.vdsvin[idx].fields.pfet3 = Iratio_int[(j*8)+3][i]; + 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]; + +// jwy for (k=0; k<8; k++) { +// jwy printf("%u ", Iratio_int[(j*8)+k][i]); +// jwy } +// jwy printf("\n"); +// jwy printf(" Vin[%d]{%d,%d}: %016llX\n", idx, i, j, pss->lpsa.vdsvin[idx].value); + + + // Byte reverse the entry into the image. + pss->lpsa.vdsvin[idx].value = revle64(pss->lpsa.vdsvin[idx].value); + } + } +} /* end fit_file */ diff --git a/src/usr/hwpf/hwp/pstates/pstates/pstate_tables.h b/src/usr/hwpf/hwp/pstates/pstates/pstate_tables.h index f4dd6b275..02081e5a4 100755 --- a/src/usr/hwpf/hwp/pstates/pstates/pstate_tables.h +++ b/src/usr/hwpf/hwp/pstates/pstates/pstate_tables.h @@ -23,7 +23,7 @@ #ifndef __PSTATE_TABLES_H__ #define __PSTATE_TABLES_H__ -// $Id: pstate_tables.h,v 1.6 2013/05/02 17:33:31 jimyac Exp $ +// $Id: pstate_tables.h,v 1.7 2013/08/13 17:13:03 jimyac Exp $ /// \file pstate_tables.h /// \brief Code used to generate Pstate tables from real or imagined chip @@ -149,8 +149,49 @@ gpst_create(GlobalPstateTable *gpst, int lpst_create(const GlobalPstateTable *gpst, LocalPstateArray *lpsa, - const uint8_t dead_zone_5mv); - + const uint8_t dead_zone_5mv, + double volt_int_vdd_bias, + double volt_int_vcs_bias); + +typedef struct IVRM_PARM_DATA { + uint32_t vin_min; // Minimum input voltage + uint32_t vin_max; // Maximum input voltage + uint32_t vin_table_step_size; // Granularity of Vin table entries + uint32_t vin_table_setsperrow; // Vin sets per Vds row + uint32_t vin_table_pfetstrperset; // PFET Strength values per Vin set + uint32_t vout_min; // Minimum regulated output voltage + uint32_t vout_max; // Maximum regulated output voltage + uint32_t vin_entries_per_vds; // Vin array entries per vds region + uint32_t vds_min_range_upper_bound; // Starting point for vds regions + uint32_t vds_step_percent; // vds region step muliplier + uint32_t vds_region_entries; // vds region array entries (in hardware) + uint32_t pfetstr_default; // Default PFET Strength with no calibration + uint32_t positive_guardband; // Plus side guardband (%) + uint32_t negative_guardband; // Negative side guardband (%) + uint32_t number_of_coefficients; // Number of coefficents in cal data + uint32_t force_pfetstr_values; // 0 - calculated; 1 = forced + uint32_t forced_pfetstr_value; // If force_pfetstr_values = 1, use this value + // 5b value used as it to fill in all entries +} ivrm_parm_data_t; + +void +build_vds_region_table(ivrm_parm_data_t* i_ivrm_parms, + PstateSuperStructure* pss); + + +void +fill_vin_table(ivrm_parm_data_t* i_ivrm_parms, + PstateSuperStructure* pss); + + +void fit_file(int n, + uint8_t version, + double C[], + ivrm_cal_data_t* cal_data); + +void write_HWtab_bin(ivrm_parm_data_t* i_ivrm_parms, + double C[], + PstateSuperStructure* pss); #endif // __ASSEMBLER__ diff --git a/src/usr/hwpf/hwp/pstates/pstates/pstates.c b/src/usr/hwpf/hwp/pstates/pstates/pstates.c index 32ee1ec94..8ef039c56 100755 --- a/src/usr/hwpf/hwp/pstates/pstates/pstates.c +++ b/src/usr/hwpf/hwp/pstates/pstates/pstates.c @@ -20,7 +20,7 @@ /* Origin: 30 */ /* */ /* IBM_PROLOG_END_TAG */ -// $Id: pstates.c,v 1.4 2013/06/12 20:02:12 mjjones Exp $ +// $Id: pstates.c,v 1.6 2013/09/17 16:36:39 jimyac Exp $ /// \file pstates.c /// \brief Pstate routines required by OCC product firmware @@ -237,6 +237,10 @@ gpst_entry(const GlobalPstateTable *gpst, int rc, index; Pstate biased_pstate; +// jwy if (SSX_ERROR_CHECK_API) { +// jwy SSX_ERROR_IF(gpst == 0, GPST_INVALID_OBJECT); +// jwy } + if (gpst == 0) { return -GPST_INVALID_OBJECT; } @@ -325,8 +329,12 @@ gpst_vdd2pstate(const GlobalPstateTable* gpst, gpst_entry_t entry_rev; // jwy +// jwy if (SSX_ERROR_CHECK_API) { +// jwy SSX_ERROR_IF(gpst == 0, GPST_INVALID_OBJECT); +// jwy } + if (gpst == 0) { - return -GPST_INVALID_OBJECT; + return -GPST_INVALID_OBJECT; } do { @@ -393,3 +401,22 @@ int freq2pState (const GlobalPstateTable* gpst, return rc; } + + + +int pstate_minmax_chk (const GlobalPstateTable* gpst, + Pstate* pstate) +{ + int rc = 0; + + // if pstate is greater than pmax, generate an error + if (*pstate > gpst_pmax(gpst)) + rc = -GPST_PSTATE_GT_GPST_PMAX; + + // if pstate is less than than pmin, clip pstate to pmin + if (*pstate < gpst_pmin(gpst) ) + *pstate = gpst_pmin(gpst); + + return rc; +} + diff --git a/src/usr/hwpf/hwp/pstates/pstates/pstates.h b/src/usr/hwpf/hwp/pstates/pstates/pstates.h index b0f8e77d4..db4f25174 100755 --- a/src/usr/hwpf/hwp/pstates/pstates/pstates.h +++ b/src/usr/hwpf/hwp/pstates/pstates/pstates.h @@ -23,7 +23,7 @@ #ifndef __PSTATES_H__ #define __PSTATES_H__ -// $Id: pstates.h,v 1.6 2013/05/02 17:33:33 jimyac Exp $ +// $Id: pstates.h,v 1.8 2013/09/17 16:36:40 jimyac Exp $ /// \file pstates.h /// \brief Pstate structures and support routines for OCC product firmware @@ -41,8 +41,11 @@ /// The Global Pstate table has 128 * 8-byte entries #define GLOBAL_PSTATE_TABLE_ENTRIES 128 -/// The Local Pstate array has 96 x 64-bit entries -#define LOCAL_PSTATE_ARRAY_ENTRIES 96 +/// The Local Pstate table has 32 x 64-bit entries +#define LOCAL_PSTATE_ARRAY_ENTRIES 32 + +/// The VDS/VIN table has 32 x 64-bit entries +#define VDSVIN_ARRAY_ENTRIES 64 /// The VRM-11 VID base voltage in micro-Volts #define VRM11_BASE_UV 1612500 @@ -56,6 +59,9 @@ /// The iVID step as an unsigned number (micro-Volts) #define IVID_STEP_UV 6250 +/// CPM Inflection Points +#define CPM_RANGES 8 + // Error/Panic codes for support routines #define VRM11_INVALID_VOLTAGE 0x00876101 @@ -78,10 +84,11 @@ #define GPST_PSTATE_CLIPPED_LOW 0x00477804 #define GPST_PSTATE_CLIPPED_HIGH 0x00477805 #define GPST_BUG 0x00477806 +#define GPST_PSTATE_GT_GPST_PMAX 0x00477807 #define LPST_INVALID_OBJECT 0x00477901 - - +#define LPST_GPST_WARNING 0x00477902 +#define LPST_INCR_CLIP_ERROR 0x00477903 /// PstateSuperStructure Magic Number /// @@ -127,6 +134,8 @@ #include <stdint.h> +#include <p8_ivrm.H> + /// A Global Pstate Table Entry, in the form of a packed 'firmware register' /// /// Global Pstate table entries are referenced by OCC firmware, for example @@ -230,6 +239,50 @@ typedef union lpst_entry { } lpst_entry_t; +/// A VDS/VIN table Entry + +typedef union vdsvin_entry { + uint64_t value; + struct { +#ifdef _BIG_ENDIAN + uint32_t high_order; + uint32_t low_order; +#else + uint32_t low_order; + uint32_t high_order; +#endif // _BIG_ENDIAN + } words; + struct { +#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 pfet7 : 5; + 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; +#endif // _BIG_ENDIAN + } fields; +} vdsvin_entry_t; + /// Standard options controlling Pstate setup and GPSM procedures typedef struct { @@ -366,7 +419,10 @@ typedef struct { typedef struct { - /// The array contents + /// The vdsvin table contents + vdsvin_entry_t vdsvin[VDSVIN_ARRAY_ENTRIES]; + + /// The local pstate table contents lpst_entry_t pstate[LOCAL_PSTATE_ARRAY_ENTRIES]; /// The number of entries defined in the Local Pstate Table @@ -416,6 +472,42 @@ typedef struct { } ResonantClockingSetup; +/// CPM Pstate ranges per mode +/// +/// These Pstate range specifications apply to all chiplets operating in the +/// same mode. + +typedef union { + + /// Forces alignment + uint64_t quad[2]; + + struct { + + /// Lower limit of each CPM calibration range + /// + /// The entries in this table are Pstates representing the + /// lowest-numbered (lowest-voltage) Pstate of each range. This is the + /// inflection point between range N and range N+1. + Pstate inflectionPoint[CPM_RANGES]; + + /// The number of ranges valid in the \a inflectionPoint table + /// + /// Validity here is defined by the original characterization + /// data. Whether or not OCC will use any particular range is managed + /// by OCC. + uint8_t validRanges; + + /// The Pstate corresponding to the upper limit of range 0. + /// + /// 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; /// The layout of the data created by the Pstate table creation firmware @@ -442,7 +534,10 @@ typedef struct { /// Resonant Clocking Setup ResonantClockingSetup resclk; - + + /// CPM Pstate ranges + CpmPstateModeRanges cpmranges; + } PstateSuperStructure; @@ -476,6 +571,9 @@ gpst_vdd2pstate(const GlobalPstateTable* gpst, Pstate* pstate, gpst_entry_t* entry); +int +pstate_minmax_chk (const GlobalPstateTable* gpst, + Pstate* pstate); /// Return the Pmin value associated with a GlobalPstateTable static inline Pstate |