diff options
Diffstat (limited to 'src/usr/hwpf/hwp/pstates/pstates/pstates.c')
-rwxr-xr-x | src/usr/hwpf/hwp/pstates/pstates/pstates.c | 395 |
1 files changed, 395 insertions, 0 deletions
diff --git a/src/usr/hwpf/hwp/pstates/pstates/pstates.c b/src/usr/hwpf/hwp/pstates/pstates/pstates.c new file mode 100755 index 000000000..32ee1ec94 --- /dev/null +++ b/src/usr/hwpf/hwp/pstates/pstates/pstates.c @@ -0,0 +1,395 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hwpf/hwp/pstates/pstates/pstates.c $ */ +/* */ +/* 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: pstates.c,v 1.4 2013/06/12 20:02:12 mjjones Exp $ + +/// \file pstates.c +/// \brief Pstate routines required by OCC product firmware + +#include "ssx.h" +#include "pgp_common.h" +#include "pstates.h" + +/// Validate a VRM11 VID code +/// +/// \param vid A VRM11 VID +/// +/// \retval 0 The VID is valid +/// +/// \retval -VID11_UNDERFLOW The Vid code is a low 'power off' VID (0 or 1) +/// +/// \retval -VID11_OVERFLOW The Vid code is a high 'power off' VID (0xfe or 0xff) + +int +vid11_validate(Vid11 vid) +{ + int rc; + + if (vid < VID11_MIN) { + + rc = -VID11_UNDERFLOW; + + } else if (vid > VID11_MAX) { + + rc = -VID11_OVERFLOW; + + } else { + + rc = 0; + + } + + return rc; +} + + +/// Bias a Pstate with saturation +/// +/// \param pstate The initial Pstate to bias +/// +/// \param bias The signed bias amount +/// +/// \param biased_pstate The final biased Pstate +/// +/// This API adds a signed bias to the \a pstate and returns the saturated sum +/// as \a biased_pstate. Any application that biases Pstates should use this +/// API rather than simple addition/subtraction. +/// +/// The following return codes are not considered errors: +/// +/// \retval 0 Success +/// +/// \retval -PSTATE_OVERFLOW The biased Pstate saturated at PSTATE_MAX. +/// +/// \retval -PSTATE_UNDERFLOW The biased Pstate saturated at PSTATE_MIN. + +int +bias_pstate(Pstate pstate, int bias, Pstate* biased_pstate) +{ + int rc, int_pstate; + + int_pstate = (int)pstate + bias; + if (int_pstate != (Pstate)int_pstate) { + if (bias < 0) { + *biased_pstate = PSTATE_MIN; + rc = -PSTATE_UNDERFLOW; + } else { + *biased_pstate = PSTATE_MAX; + rc = -PSTATE_OVERFLOW; + } + } else { + *biased_pstate = int_pstate; + rc = 0; + } + + return rc; +} + + +/// Bias a DPLL frequency code with saturation and bounds checking +/// +/// \param fcode The initial frequency code to bias +/// +/// \param bias The signed bias amount +/// +/// \param biased_fcode The final biased frequency code +/// +/// This API adds a signed bias to the \a fcode and returns the saturated and +/// bounded sum as \a biased_fcode. Any application that biases frequency +/// codes should use this API rather than simple addition/subtraction. +/// +/// The following return codes are not considered errors: +/// +/// \retval 0 Success +/// +/// \retval -DPLL_OVERFLOW The biased frequency code saturated at DPLL_MAX. +/// +/// \retval -DPLL_UNDERFLOW The biased frequency code saturated at DPLL_MIN. + +int +bias_frequency(DpllCode fcode, int bias, DpllCode* biased_fcode) +{ + int rc; + unsigned uint_fcode; + + uint_fcode = (unsigned)fcode + bias; + if (uint_fcode != (DpllCode)uint_fcode) { + if (bias < 0) { + *biased_fcode = DPLL_MIN; + rc = -DPLL_UNDERFLOW; + } else { + *biased_fcode = DPLL_MAX; + rc = -DPLL_OVERFLOW; + } + } else if (uint_fcode < DPLL_MIN) { + *biased_fcode = DPLL_MIN; + rc = -DPLL_UNDERFLOW; + } else { + *biased_fcode = uint_fcode; + rc = 0; + } + + return rc; +} + + +/// Bias a VRM11 VID code with saturation and bounds checking +/// +/// \param vid The initial vid code to bias +/// +/// \param bias The signed bias amount +/// +/// \param biased_vid The final biased VID code +/// +/// This API adds a signed bias to the \a vid and returns the saturated and +/// bounded sum as \a biased_vid. Any application that biases VID codes +/// should use this API rather than simple addition/subtraction. +/// +/// The following return codes are not considered errors: +/// +/// \retval 0 Success +/// +/// \retval -VID11_OVERFLOW The biased VID code saturated at VID11_MAX. +/// +/// \retval -VID11_UNDERFLOW The biased VID code saturated at VID11__MIN. + +int +bias_vid11(Vid11 vid, int bias, Vid11* biased_vid) +{ + int rc; + unsigned uint_vid; + + uint_vid = (unsigned)vid + bias; + if (uint_vid != (DpllCode)uint_vid) { + if (bias < 0) { + *biased_vid = VID11_MIN; + rc = -VID11_UNDERFLOW; + } else { + *biased_vid = VID11_MAX; + rc = -VID11_OVERFLOW; + } + } else { + + rc = vid11_validate(uint_vid); + *biased_vid = uint_vid; + + } + + return rc; +} + + +/// Retrieve an entry from the Global Pstate Table abstraction +/// +/// \param gpst An initialized GlobalPstateTable structure. +/// +/// \param pstate The Pstate index of the entry to fetch +/// +/// \param bias This is a signed bias. The entry searched is the \a pstate + +/// \a bias entry. +/// +/// \param entry A pointer to a gpst_entry_t to hold the returned data. +/// +/// This routine functions similar to PMC harwdare. When a Pstate is +/// requested the index is first biased (under/over-volted) and clipped to the +/// defined bounds, then the Pstate entry is returned. +/// +/// The following return codes are not considered errors: +/// +/// \retval 0 Success +/// +/// \retval -GPST_PSTATE_CLIPPED_HIGH The requested Pstate does not exist in +/// the table. The maximum Pstate entry in the table has been returned. +/// +/// \retval -GPST_PSTATE_CLIPPED_LOW The requested Pstate does not exist in +/// the table. The minimum Pstate entry in the table has been returned. +/// +/// The following return codes are considered errors: +/// +/// \retval -GPST_INVALID_OBJECT The Global Pstate Table is either null (0) or +/// otherwise invalid. + +int +gpst_entry(const GlobalPstateTable *gpst, + const Pstate pstate, + int bias, + gpst_entry_t *entry) +{ + int rc, index; + Pstate biased_pstate; + + if (gpst == 0) { + return -GPST_INVALID_OBJECT; + } + + rc = bias_pstate(pstate, bias, &biased_pstate); + + if ((rc == -PSTATE_UNDERFLOW) || (pstate < gpst_pmin(gpst))) { + + rc = -GPST_PSTATE_CLIPPED_LOW; + index = 0; + + } else if ((rc == -PSTATE_OVERFLOW) || (pstate > gpst_pmax(gpst))) { + + rc = -GPST_PSTATE_CLIPPED_HIGH; + index = gpst->entries - 1; + + } else { + + rc = 0; + index = pstate - gpst_pmin(gpst); + + } + + *entry = gpst->pstate[index]; + + return rc; +} + + +/// Translate a Vdd VID code to the closest Pstate in a Global Pstate table. +/// +/// \param gpst The GlobalPstateTable to search +/// +/// \param vdd A VID code representing an external VDD voltage +/// +/// \param pstate The Pstate most closely matching the \a vid. +/// +/// \param entry The GlobalPstateTable entry of the returned \a pstate. +/// +/// This routine assumes that Pstate voltages increase monotonically from +/// lower to higher Pstates. The algorithm operates from lowest to highest +/// voltage, scanning until the Pstate voltage is >= the VID voltage. Thus +/// the algorithm effectively rounds up voltage (unless clipped at the highest +/// Pstate). +/// +/// The following return codes are not considered errors: +/// +/// \retval 0 Success +/// +/// \retval -GPST_PSTATE_CLIPPED_HIGH The requested voltage does not exist in +/// the table. The highest legal Pstate is returned. +/// +/// \retval -GPST_PSTATE_CLIPPED_LOW The requested voltage does not exist in +/// the table. The lowest legal Pstate in the table is returned. +/// +/// The following return codes are considered errors: +/// +/// \retval -VRM_INVALID_VOLTAGE The \a vid is invalid. +/// +/// \retval -GPST_INVALID_OBJECT The \a gpst argument is NULL (0). + +// Recall that VID codes _decrease_ as voltage _increases_ + +#ifdef _BIG_ENDIAN + +#define revle16(x) x +#define revle32(x) x +#define revle64(x) x + +#else + +uint16_t revle16(uint16_t i_x); +uint32_t revle32(uint32_t i_x); +uint64_t revle64(uint64_t i_x); + +#endif + +int +gpst_vdd2pstate(const GlobalPstateTable* gpst, + const Vid11 vdd, + Pstate* pstate, + gpst_entry_t* entry) +{ + size_t i; + int rc; + gpst_entry_t entry_rev; // jwy + + + if (gpst == 0) { + return -GPST_INVALID_OBJECT; + } + + do { + rc =vid11_validate(vdd); + if (rc) break; + + // Search for the Pstate that contains (close to) the requested + // voltage, then handle special cases. + + for (i = 0; i < gpst->entries; i++) { + entry_rev.value = revle64(gpst->pstate[i].value); // jwy + +// jwy if (gpst->pstate[i].fields.evid_vdd <= vdd) { + if (entry_rev.fields.evid_vdd <= vdd) { // jwy + break; + } + } + + if (i == gpst->entries) { + + *pstate = gpst_pmax(gpst); + *entry = gpst->pstate[i - 1]; + rc = -GPST_PSTATE_CLIPPED_HIGH; + +// jwy } else if ((i == 0) && (gpst->pstate[i].fields.evid_vdd < vdd)) { + } else if ((i == 0) && (entry_rev.fields.evid_vdd < vdd)) { + + *pstate = gpst_pmin(gpst); + *entry = gpst->pstate[0]; + rc = -GPST_PSTATE_CLIPPED_LOW; + + } else { + + rc = bias_pstate(gpst_pmin(gpst), i, pstate); + if (rc) break; + + *entry = gpst->pstate[i]; + } + } while (0); + return rc; +} + +int freq2pState (const GlobalPstateTable* gpst, + const uint32_t freq_khz, + Pstate* pstate) +{ + int rc = 0; + int32_t pstate32 = 0; + + // ---------------------------------- + // compute pstate for given frequency + // ---------------------------------- + pstate32 = ((int32_t)((freq_khz - revle32(gpst->pstate0_frequency_khz)))) / (int32_t)revle32(gpst->frequency_step_khz); + *pstate = (Pstate)pstate32; + + // ------------------------------ + // perform pstate bounds checking + // ------------------------------ + if (pstate32 < PSTATE_MIN) + rc = -PSTATE_LT_PSTATE_MIN; + + if (pstate32 > PSTATE_MAX) + rc = -PSTATE_GT_PSTATE_MAX; + + return rc; +} |