diff options
author | Elliott Dahle <dedahle@us.ibm.com> | 2013-06-12 09:59:55 -0500 |
---|---|---|
committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2013-07-08 10:31:17 -0500 |
commit | 7a2c484cc9c574302beb70cfff449bb40d26c2e2 (patch) | |
tree | 0c4cbf7a0be714163f639ac1eacf2c151c360395 | |
parent | 0e8072c8c3aa49ce9e75c468f4e14e80893d56f0 (diff) | |
download | talos-hostboot-7a2c484cc9c574302beb70cfff449bb40d26c2e2.tar.gz talos-hostboot-7a2c484cc9c574302beb70cfff449bb40d26c2e2.zip |
Integrate pstate-building HWPs into Hostboot.
Transferred pstate files from FSP code.
Edited files to compile on Hostboot.
Change-Id: I04ff6ba489e77277afe27cff9544aea1367c150e
RTC: 73048
Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/4979
Tested-by: Jenkins Server
Reviewed-by: MIKE J. JONES <mjjones@us.ibm.com>
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
18 files changed, 3648 insertions, 25 deletions
diff --git a/src/usr/hwpf/hwp/build_winkle_images/p8_set_pore_bar/pgp_common.h b/src/usr/hwpf/hwp/include/pgp_common.h index 2fb33877a..9cdeb185c 100644 --- a/src/usr/hwpf/hwp/build_winkle_images/p8_set_pore_bar/pgp_common.h +++ b/src/usr/hwpf/hwp/include/pgp_common.h @@ -1,26 +1,25 @@ -/* IBM_PROLOG_BEGIN_TAG - * This is an automatically generated prolog. - * - * $Source: src/usr/hwpf/hwp/build_winkle_images/proc_set_pore_bar/pgp_common.h $ - * - * IBM CONFIDENTIAL - * - * COPYRIGHT International Business Machines Corp. 2012 - * - * 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 other- - * wise divested of its trade secrets, irrespective of what has - * been deposited with the U.S. Copyright Office. - * - * Origin: 30 - * - * IBM_PROLOG_END_TAG - */ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hwpf/hwp/include/pgp_common.h $ */ +/* */ +/* IBM CONFIDENTIAL */ +/* */ +/* COPYRIGHT International Business Machines Corp. 2012,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: pgp_common.h,v 1.2 2012/08/13 16:11:58 stillgs Exp $ #ifndef __PGP_COMMON_H__ diff --git a/src/usr/hwpf/hwp/makefile b/src/usr/hwpf/hwp/makefile index 7a611a9b0..d2e881656 100644 --- a/src/usr/hwpf/hwp/makefile +++ b/src/usr/hwpf/hwp/makefile @@ -47,7 +47,8 @@ SUBDIRS = dmi_training.d sbe_centaur_init.d mc_config.d \ dram_training.d activate_powerbus.d build_winkle_images.d \ core_activate.d dram_initialization.d edi_ei_initialization.d \ establish_system_smp.d bus_training.d occ.d tod_init.d \ - nest_chiplets.d start_payload.d thread_activate.d slave_sbe.d + nest_chiplets.d start_payload.d thread_activate.d slave_sbe.d \ + pstates.d include mvpd_accessors/mvpd.mk include utility_procedures/utils.mk diff --git a/src/usr/hwpf/hwp/pstates/makefile b/src/usr/hwpf/hwp/pstates/makefile new file mode 100644 index 000000000..529f366a6 --- /dev/null +++ b/src/usr/hwpf/hwp/pstates/makefile @@ -0,0 +1,57 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/usr/hwpf/hwp/pstates/makefile $ +# +# 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 +ROOTPATH = ../../../../.. + +MODULE = pstates + +## support for Targeting and fapi +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/ecmddatabuffer +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/hwpf/fapi +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/hwpf/plat +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/hwpf/hwp + +## pointer to common HWP files +EXTRAINCDIR += ${ROOTPATH}/src/usr/hwpf/hwp/include + +## NOTE: add the base istep dir here. +##@ EXTRAINCDIR += ${ROOTPATH}/src/usr/hwpf/hwp/@istepname +EXTRAINCDIR += ${ROOTPATH}/src/usr/hwpf/hwp/pstates + +## Include sub dirs +## NOTE: add a new EXTRAINCDIR when you add a new HWP +##@ EXTRAINCDIR += ${ROOTPATH}/src/usr/hwpf/hwp/??? +EXTRAINCDIR += ${ROOTPATH}/src/usr/hwpf/hwp/pstates/pstates + +## NOTE: add new object files when you add a new HWP +OBJS = gpstCheckByte.o \ + lab_pstates.o \ + p8_build_pstate_datablock.o \ + proc_get_voltage.o \ + pstates.o \ + pstate_tables.o + +## NOTE: add a new directory onto the vpaths when you add a new HWP +##@ VPATH += ${ROOTPATH}/src/usr/hwpf/hwp/??? +VPATH += ${ROOTPATH}/src/usr/hwpf/hwp/pstates/pstates + +include ${ROOTPATH}/config.mk diff --git a/src/usr/hwpf/hwp/pstates/pstates/gpstCheckByte.c b/src/usr/hwpf/hwp/pstates/pstates/gpstCheckByte.c new file mode 100755 index 000000000..bd4f88f12 --- /dev/null +++ b/src/usr/hwpf/hwp/pstates/pstates/gpstCheckByte.c @@ -0,0 +1,229 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hwpf/hwp/pstates/pstates/gpstCheckByte.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: gpstCheckByte.c,v 1.1 2012/10/16 16:30:15 jimyac Exp $ + +/// \file gpamCheckByte.c +/// \brief Generate Pstate table check byte - Generated by genGpstCheckByte.tcl + +#include <stdint.h> + +#define BIT(x, n) (((x) >> (63 - (n))) & 1) + +uint8_t +gpstCheckByte(uint64_t gpstEntry) +{ + int cb[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + + cb[0] ^= BIT(gpstEntry, 0); + cb[0] ^= BIT(gpstEntry, 1); + cb[0] ^= BIT(gpstEntry, 2); + cb[0] ^= BIT(gpstEntry, 3); + cb[0] ^= BIT(gpstEntry, 4); + cb[0] ^= BIT(gpstEntry, 5); + cb[0] ^= BIT(gpstEntry, 6); + cb[0] ^= BIT(gpstEntry, 7); + cb[0] ^= BIT(gpstEntry, 24); + cb[0] ^= BIT(gpstEntry, 25); + cb[0] ^= BIT(gpstEntry, 26); + cb[0] ^= BIT(gpstEntry, 28); + cb[0] ^= BIT(gpstEntry, 33); + cb[0] ^= BIT(gpstEntry, 38); + cb[0] ^= BIT(gpstEntry, 42); + cb[0] ^= BIT(gpstEntry, 43); + cb[0] ^= BIT(gpstEntry, 44); + cb[0] ^= BIT(gpstEntry, 45); + cb[0] ^= BIT(gpstEntry, 52); + cb[0] ^= BIT(gpstEntry, 53); + cb[0] ^= BIT(gpstEntry, 54); + cb[0] ^= BIT(gpstEntry, 55); + cb[1] ^= BIT(gpstEntry, 0); + cb[1] ^= BIT(gpstEntry, 3); + cb[1] ^= BIT(gpstEntry, 4); + cb[1] ^= BIT(gpstEntry, 7); + cb[1] ^= BIT(gpstEntry, 8); + cb[1] ^= BIT(gpstEntry, 9); + cb[1] ^= BIT(gpstEntry, 10); + cb[1] ^= BIT(gpstEntry, 11); + cb[1] ^= BIT(gpstEntry, 12); + cb[1] ^= BIT(gpstEntry, 13); + cb[1] ^= BIT(gpstEntry, 14); + cb[1] ^= BIT(gpstEntry, 15); + cb[1] ^= BIT(gpstEntry, 32); + cb[1] ^= BIT(gpstEntry, 33); + cb[1] ^= BIT(gpstEntry, 34); + cb[1] ^= BIT(gpstEntry, 36); + cb[1] ^= BIT(gpstEntry, 41); + cb[1] ^= BIT(gpstEntry, 46); + cb[1] ^= BIT(gpstEntry, 50); + cb[1] ^= BIT(gpstEntry, 51); + cb[1] ^= BIT(gpstEntry, 52); + cb[1] ^= BIT(gpstEntry, 53); + cb[2] ^= BIT(gpstEntry, 4); + cb[2] ^= BIT(gpstEntry, 5); + cb[2] ^= BIT(gpstEntry, 6); + cb[2] ^= BIT(gpstEntry, 7); + cb[2] ^= BIT(gpstEntry, 8); + cb[2] ^= BIT(gpstEntry, 11); + cb[2] ^= BIT(gpstEntry, 12); + cb[2] ^= BIT(gpstEntry, 15); + cb[2] ^= BIT(gpstEntry, 16); + cb[2] ^= BIT(gpstEntry, 17); + cb[2] ^= BIT(gpstEntry, 18); + cb[2] ^= BIT(gpstEntry, 19); + cb[2] ^= BIT(gpstEntry, 20); + cb[2] ^= BIT(gpstEntry, 21); + cb[2] ^= BIT(gpstEntry, 22); + cb[2] ^= BIT(gpstEntry, 23); + cb[2] ^= BIT(gpstEntry, 40); + cb[2] ^= BIT(gpstEntry, 41); + cb[2] ^= BIT(gpstEntry, 42); + cb[2] ^= BIT(gpstEntry, 44); + cb[2] ^= BIT(gpstEntry, 49); + cb[2] ^= BIT(gpstEntry, 54); + cb[3] ^= BIT(gpstEntry, 2); + cb[3] ^= BIT(gpstEntry, 3); + cb[3] ^= BIT(gpstEntry, 4); + cb[3] ^= BIT(gpstEntry, 5); + cb[3] ^= BIT(gpstEntry, 12); + cb[3] ^= BIT(gpstEntry, 13); + cb[3] ^= BIT(gpstEntry, 14); + cb[3] ^= BIT(gpstEntry, 15); + cb[3] ^= BIT(gpstEntry, 16); + cb[3] ^= BIT(gpstEntry, 19); + cb[3] ^= BIT(gpstEntry, 20); + cb[3] ^= BIT(gpstEntry, 23); + cb[3] ^= BIT(gpstEntry, 24); + cb[3] ^= BIT(gpstEntry, 25); + cb[3] ^= BIT(gpstEntry, 26); + cb[3] ^= BIT(gpstEntry, 27); + cb[3] ^= BIT(gpstEntry, 28); + cb[3] ^= BIT(gpstEntry, 29); + cb[3] ^= BIT(gpstEntry, 30); + cb[3] ^= BIT(gpstEntry, 31); + cb[3] ^= BIT(gpstEntry, 48); + cb[3] ^= BIT(gpstEntry, 49); + cb[3] ^= BIT(gpstEntry, 50); + cb[3] ^= BIT(gpstEntry, 52); + cb[4] ^= BIT(gpstEntry, 1); + cb[4] ^= BIT(gpstEntry, 6); + cb[4] ^= BIT(gpstEntry, 10); + cb[4] ^= BIT(gpstEntry, 11); + cb[4] ^= BIT(gpstEntry, 12); + cb[4] ^= BIT(gpstEntry, 13); + cb[4] ^= BIT(gpstEntry, 20); + cb[4] ^= BIT(gpstEntry, 21); + cb[4] ^= BIT(gpstEntry, 22); + cb[4] ^= BIT(gpstEntry, 23); + cb[4] ^= BIT(gpstEntry, 24); + cb[4] ^= BIT(gpstEntry, 27); + cb[4] ^= BIT(gpstEntry, 28); + cb[4] ^= BIT(gpstEntry, 31); + cb[4] ^= BIT(gpstEntry, 32); + cb[4] ^= BIT(gpstEntry, 33); + cb[4] ^= BIT(gpstEntry, 34); + cb[4] ^= BIT(gpstEntry, 35); + cb[4] ^= BIT(gpstEntry, 36); + cb[4] ^= BIT(gpstEntry, 37); + cb[4] ^= BIT(gpstEntry, 38); + cb[4] ^= BIT(gpstEntry, 39); + cb[5] ^= BIT(gpstEntry, 0); + cb[5] ^= BIT(gpstEntry, 1); + cb[5] ^= BIT(gpstEntry, 2); + cb[5] ^= BIT(gpstEntry, 4); + cb[5] ^= BIT(gpstEntry, 9); + cb[5] ^= BIT(gpstEntry, 14); + cb[5] ^= BIT(gpstEntry, 18); + cb[5] ^= BIT(gpstEntry, 19); + cb[5] ^= BIT(gpstEntry, 20); + cb[5] ^= BIT(gpstEntry, 21); + cb[5] ^= BIT(gpstEntry, 28); + cb[5] ^= BIT(gpstEntry, 29); + cb[5] ^= BIT(gpstEntry, 30); + cb[5] ^= BIT(gpstEntry, 31); + cb[5] ^= BIT(gpstEntry, 32); + cb[5] ^= BIT(gpstEntry, 35); + cb[5] ^= BIT(gpstEntry, 36); + cb[5] ^= BIT(gpstEntry, 39); + cb[5] ^= BIT(gpstEntry, 40); + cb[5] ^= BIT(gpstEntry, 41); + cb[5] ^= BIT(gpstEntry, 42); + cb[5] ^= BIT(gpstEntry, 43); + cb[5] ^= BIT(gpstEntry, 44); + cb[5] ^= BIT(gpstEntry, 45); + cb[5] ^= BIT(gpstEntry, 46); + cb[5] ^= BIT(gpstEntry, 47); + cb[6] ^= BIT(gpstEntry, 8); + cb[6] ^= BIT(gpstEntry, 9); + cb[6] ^= BIT(gpstEntry, 10); + cb[6] ^= BIT(gpstEntry, 12); + cb[6] ^= BIT(gpstEntry, 17); + cb[6] ^= BIT(gpstEntry, 22); + cb[6] ^= BIT(gpstEntry, 26); + cb[6] ^= BIT(gpstEntry, 27); + cb[6] ^= BIT(gpstEntry, 28); + cb[6] ^= BIT(gpstEntry, 29); + cb[6] ^= BIT(gpstEntry, 36); + cb[6] ^= BIT(gpstEntry, 37); + cb[6] ^= BIT(gpstEntry, 38); + cb[6] ^= BIT(gpstEntry, 39); + cb[6] ^= BIT(gpstEntry, 40); + cb[6] ^= BIT(gpstEntry, 43); + cb[6] ^= BIT(gpstEntry, 44); + cb[6] ^= BIT(gpstEntry, 47); + cb[6] ^= BIT(gpstEntry, 48); + cb[6] ^= BIT(gpstEntry, 49); + cb[6] ^= BIT(gpstEntry, 50); + cb[6] ^= BIT(gpstEntry, 51); + cb[6] ^= BIT(gpstEntry, 52); + cb[6] ^= BIT(gpstEntry, 53); + cb[6] ^= BIT(gpstEntry, 54); + cb[6] ^= BIT(gpstEntry, 55); + cb[7] ^= BIT(gpstEntry, 16); + cb[7] ^= BIT(gpstEntry, 17); + cb[7] ^= BIT(gpstEntry, 18); + cb[7] ^= BIT(gpstEntry, 20); + cb[7] ^= BIT(gpstEntry, 25); + cb[7] ^= BIT(gpstEntry, 30); + cb[7] ^= BIT(gpstEntry, 34); + cb[7] ^= BIT(gpstEntry, 35); + cb[7] ^= BIT(gpstEntry, 36); + cb[7] ^= BIT(gpstEntry, 37); + cb[7] ^= BIT(gpstEntry, 44); + cb[7] ^= BIT(gpstEntry, 45); + cb[7] ^= BIT(gpstEntry, 46); + cb[7] ^= BIT(gpstEntry, 47); + cb[7] ^= BIT(gpstEntry, 48); + cb[7] ^= BIT(gpstEntry, 51); + cb[7] ^= BIT(gpstEntry, 52); + cb[7] ^= BIT(gpstEntry, 55); + return + (cb[0] << 7) | + (cb[1] << 6) | + (cb[2] << 5) | + (cb[3] << 4) | + (cb[4] << 3) | + (cb[5] << 2) | + (cb[6] << 1) | + (cb[7] << 0); +} + diff --git a/src/usr/hwpf/hwp/pstates/pstates/lab_pstates.c b/src/usr/hwpf/hwp/pstates/pstates/lab_pstates.c new file mode 100755 index 000000000..2e7767927 --- /dev/null +++ b/src/usr/hwpf/hwp/pstates/pstates/lab_pstates.c @@ -0,0 +1,486 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hwpf/hwp/pstates/pstates/lab_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: lab_pstates.c,v 1.7 2013/06/12 20:01:35 mjjones Exp $ + +/// \file lab_pstates.c +/// \brief Lab-only (as opposed to product-procedure) support for Pstates. +/// +/// Lab-only Pstate support is separated from generic Pstate support to reduce +/// the size of OCC product firmware images. + +#include "ssx.h" +// jwy #include "ppc32.h" +#include "lab_pstates.h" +// jwy #include "pmc_register_addresses.h" +// jwy #include "pmc_firmware_registers.h" +// jwy #include "pcbs_register_addresses.h" +// jwy #include "pcbs_firmware_registers.h" + +/// Convert a voltage in microvolts to a VRM-11 VID code, rounding the implied +/// voltage as required. +/// +/// \param v_uv Voltage in micro-volts +/// +/// \param round \a round >= 0 indicate round voltage up, while \a round < 0 +/// implies round voltage down +/// +/// \param vrm11_vid A pointer to the location of the final VID code. This +/// location is updated even if the final VID code is invalid. +/// +/// \bug Confirm if the 1.6125V offset is still valid for PgP + +// Recall that VRM11 is inverted; rounding a VID code up rounds down the +// voltage. + +int +vuv2vrm11(uint32_t v_uv, int round, uint8_t *vrm11_vid) +{ + int32_t offset, vid; + + offset = VRM11_BASE_UV - v_uv; + vid = offset / VRM11_STEP_UV; + + if (((offset % VRM11_STEP_UV) != 0) && (round < 0)) { + vid++; + } + + *vrm11_vid = vid; + return vid11_validate(vid); +} + + +/// Convert a VRM-11 VID code to a voltage in microvolts + +int +vrm112vuv(uint8_t vrm11_vid, uint32_t *v_uv) +{ + *v_uv= VRM11_BASE_UV - (vrm11_vid * VRM11_STEP_UV); + return vid11_validate(vrm11_vid); +} + + +/// Convert a voltage in microvolts to an internal VID code, rounding the +/// implied voltage as required. +/// +/// \param v_uv Voltage in micro-volts +/// +/// \param round \a round >= 0 indicate round voltage up, while \a round < 0 +/// implies round voltage down +/// +/// \param ivid A pointer to the location of the final VID code. This +/// location is updated even the event of errors. +/// +/// \retval 0 Success +/// +/// \retval -IVID_INVALID_VOLTAGE If \a v_uv can not be converted to a legal +/// IVID encoding. + +int +vuv2ivid(uint32_t v_uv, int round, uint8_t *ivid) +{ + int rc; + int32_t offset, vid; + + offset = v_uv - IVID_BASE_UV; + vid = offset / IVID_STEP_UV; + + if (((offset % IVID_STEP_UV) != 0) && (round >= 0)) { + vid++; + } + + *ivid = vid; + if ((vid < 0) || (vid > 0x7f)) { + rc = -IVID_INVALID_VOLTAGE; + } else { + rc = 0; + } + return rc; +} + + +/// Convert an iVID code to a voltage in microvolts + +int +ivid2vuv(uint8_t ivid, uint32_t *v_uv) +{ + if (ivid > 0x7f) { + return -IVID_INVALID_VOLTAGE; + } else { + *v_uv= IVID_BASE_UV + (ivid * IVID_STEP_UV); + return 0; + } +} + +/// Format a voltage in microvolts as 10 microvolts into a user-supplied +/// string.. The string \a s must be able to store at least +/// FORMAT_10UV_STRLEN characters. + +int +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. + +int +sprintf_ivid(char *s, uint8_t ivid) +{ + int rc; + uint32_t v_uv; + + if ((rc = ivid2vuv(ivid, &v_uv)) != 0) { + return rc; + } + return sprintf_10uv(s, v_uv); +} + +/// 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. + +int +sprintf_vrm11(char *s, uint8_t vrm11) +{ + int rc; + uint32_t v_uv; + + if ((rc = vrm112vuv(vrm11, &v_uv)) != 0) { + strcpy(s, FORMAT_10UV_ERROR); + } else { + rc = sprintf_10uv(s, v_uv); + } + return rc; +} + +#ifdef FAPIECMD + +/// Format a voltage in microvolts as 10 microvolts to a stream. + +int +fprintf_10uv(FILE *stream, uint32_t v_uv) +{ + int rc; + char s[FORMAT_10UV_STRLEN]; + + rc = sprintf_10uv(s, v_uv); + if (rc > 0) { + rc = fputs(s, stream); + } + return rc; +} + + +/// Format a VRM-11 VID code as 10 microvolts to a stream. + +int +fprintf_vrm11(FILE *stream, uint8_t vrm11) +{ + int rc; + char s[FORMAT_10UV_STRLEN]; + + rc = sprintf_vrm11(s, vrm11); + if (rc > 0) { + rc = fputs(s, stream); + } + return rc; +} + + +/// Format an iVID code as 10 microvolts to a stream. + +int +fprintf_ivid(FILE *stream, uint8_t ivid) +{ + int rc; + char s[FORMAT_10UV_STRLEN]; + + rc = sprintf_ivid(s, ivid); + if (rc > 0) { + rc = fputs(s, stream); + } + return rc; +} + + +// NB: The gpst_print() routine only needs the revle* functions when compiled +// into little-endian Linux applications, which must provide their +// implementations. + +#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 + + +/// Print a GlobalPstateTable structure on a given stream +/// +/// \param stream The output stream +/// +/// \param gpst The Global Pstate Table to print + +void +gpst_print(FILE *stream, GlobalPstateTable *gpst) +{ + // Endian-corrected scalar Pstate fields + + uint32_t options; + uint32_t pstate0_frequency_khz, frequency_step_khz; + uint8_t entries, pstate_stepsize, vrm_stepdelay_range, vrm_stepdelay_value; + Pstate pmin, pvsafe, psafe; + + // Endian-corrected vector Pstate fields + + gpst_entry_t entry; + + // Other local variables + + int i; + uint8_t evid_vdd, evid_vcs, evid_vdd_eff, evid_vcs_eff, + maxreg_vdd, maxreg_vcs; + int8_t pstate; + char evid_vdd_str[FORMAT_10UV_STRLEN]; + char evid_vcs_str[FORMAT_10UV_STRLEN]; + char evid_vdd_eff_str[FORMAT_10UV_STRLEN]; + char evid_vcs_eff_str[FORMAT_10UV_STRLEN]; + char maxreg_vdd_str[FORMAT_10UV_STRLEN]; + char maxreg_vcs_str[FORMAT_10UV_STRLEN]; + + // Get endian-corrected scalars + + options = revle32(gpst->options.options); + pstate0_frequency_khz = revle32(gpst->pstate0_frequency_khz); + frequency_step_khz = revle32(gpst->frequency_step_khz); + entries = gpst->entries; + pstate_stepsize = gpst->pstate_stepsize; + vrm_stepdelay_range = gpst->vrm_stepdelay_range; + vrm_stepdelay_value = gpst->vrm_stepdelay_value; + pmin = gpst->pmin; + pvsafe = gpst->pvsafe; + psafe = gpst->psafe; + + + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\n"); + fprintf(stream, "Global Pstate Table @ %p\n", gpst); + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\n"); + fprintf(stream, "%d Entries from %+d to %+d\n", + entries, gpst_pmin(gpst), gpst_pmax(gpst)); + fprintf(stream, "Frequency Step = %u KHz\n", frequency_step_khz); + fprintf(stream, "Pstate 0 Frequency = %u KHz\n", pstate0_frequency_khz); + fprintf(stream, "Pstate 0 Frequency Code (per core) :"); + for (i = 0; i < PGP_NCORES; i++) { + if ((i != 0) && ((i % 4) == 0)) { + fprintf(stream, "\n "); + } + fprintf(stream, " 0x%03x", revle16(gpst->pstate0_frequency_code[i])); + } + fprintf(stream, "\n"); + fprintf(stream, "DPLL Fmax Bias (per core) :"); + for (i = 0; i < PGP_NCORES; i++) { + fprintf(stream, " %d", gpst->dpll_fmax_bias[i]); + } + fprintf(stream, "\n"); + fprintf(stream, "Pstate Step Size %u, VRM Range %u, VRM Delay %u\n", + pstate_stepsize, vrm_stepdelay_range, vrm_stepdelay_value); + fprintf(stream, "Pvsafe %d, Psafe %d\n", pvsafe, psafe); + + if (options == 0) { + fprintf(stream, "No Options\n"); + } else { + fprintf(stream, "Options 0x%08x:\n", options); + if (options & PSTATE_NO_COPY_GPST) { + fprintf(stream, " PSTATE_NO_COPY_GPST\n"); + } + if (options & PSTATE_NO_INSTALL_GPST) { + fprintf(stream, " PSTATE_NO_INSTALL_GPST\n"); + } + if (options & PSTATE_NO_INSTALL_LPSA) { + fprintf(stream, " PSTATE_NO_INSTALL_LPSA\n"); + } + if (options & PSTATE_NO_INSTALL_RESCLK) { + fprintf(stream, " PSTATE_NO_INSTALL_RESCLK\n"); + } + if (options & PSTATE_FORCE_INITIAL_PMIN) { + fprintf(stream, " PSTATE_FORCE_INITIAL_PMIN\n"); + } + } + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\n"); + fprintf(stream, + " I Pstate F(MHz) evid_vdd(V) evid_vcs(V) evid_vdd_eff(V) evid_vcs_eff(V) maxreg_vdd(V) maxreg_vcs(V)\n" + "---------------------------------------------------------------------------------------------------------\n"); + + for (i = gpst->entries - 1; i >= 0; i--) { + + entry.value = revle64(gpst->pstate[i].value); + + evid_vdd = entry.fields.evid_vdd; + sprintf_vrm11(evid_vdd_str, evid_vdd); + + evid_vcs = entry.fields.evid_vcs; + sprintf_vrm11(evid_vcs_str, evid_vcs); + + evid_vdd_eff = entry.fields.evid_vdd_eff; + sprintf_ivid(evid_vdd_eff_str, evid_vdd_eff); + + evid_vcs_eff = entry.fields.evid_vcs_eff; + sprintf_ivid(evid_vcs_eff_str, evid_vcs_eff); + + maxreg_vdd = entry.fields.maxreg_vdd; + sprintf_ivid(maxreg_vdd_str, maxreg_vdd); + + maxreg_vcs = entry.fields.maxreg_vcs; + sprintf_ivid(maxreg_vcs_str, maxreg_vcs); + + pstate = gpst_pmin(gpst) + i; + + fprintf(stream, + "%3d %+4d " + "%4d " + "0x%02x %s " + "0x%02x %s " + "0x%02x %s " + "0x%02x %s " + "0x%02x %s " + "0x%02x %s\n", + i, pstate, + (pstate0_frequency_khz + (frequency_step_khz * pstate)) / 1000, + evid_vdd, evid_vdd_str, + evid_vcs, evid_vcs_str, + evid_vdd_eff, evid_vdd_eff_str, + evid_vcs_eff, evid_vcs_eff_str, + maxreg_vdd, maxreg_vdd_str, + maxreg_vcs, maxreg_vcs_str); + } + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\n"); +} + + +/// Print a LocalPstateArray structure on a given stream +/// +/// \param stream The output stream +/// +/// \param lpsa The Local Pstate Array to print +/// +/// \todo Replace the hex dump with a decoded Local Pstate Table + ivrm table + +void +lpsa_print(FILE* stream, LocalPstateArray* lpsa) +{ + int i; + + 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_lowering); + + 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"); +} + + +/// Print a Resonant Clocking Setup structure on a given stream +/// +/// \param stream The output stream +/// +/// \param resclk The ResonantClockingSetup to print + +void +resclk_print(FILE* stream, ResonantClockingSetup* resclk) +{ + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\n"); + fprintf(stream, "Resonant Clocking Setup @ %p\n", resclk); + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\n"); + + fprintf(stream, "Full Clock Sector Buffer Pstate : %d\n", + resclk->full_csb_ps); + fprintf(stream, "Low Frequency Resonant Lower Pstate : %d\n", + resclk->res_low_lower_ps); + fprintf(stream, "Low Frequency Resonant Upper Pstate : %d\n", + resclk->res_low_upper_ps); + fprintf(stream, "High Frequency Resonant Lower Pstate : %d\n", + resclk->res_high_lower_ps); + fprintf(stream, "High Frequency Resonant Upper Pstate : %d\n", + resclk->res_high_upper_ps); + + fprintf(stream, + "---------------------------------------------------------------------------------------------------------\n"); +} + + +/// Print a PstateSuperStructure on a given stream +/// +/// \param stream The output stream +/// +/// \param pss The PstateSuperStructure to print + +void +pss_print(FILE* stream, PstateSuperStructure* pss) +{ + fprintf(stream, + "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); + fprintf(stream, "PstateSuperStructure @ %p\n", pss); + fprintf(stream, + "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); + + gpst_print(stream, &(pss->gpst)); + lpsa_print(stream, &(pss->lpsa)); + resclk_print(stream, &(pss->resclk)); + + fprintf(stream, + "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); +} + +#endif // FAPIECMD + + diff --git a/src/usr/hwpf/hwp/pstates/pstates/lab_pstates.h b/src/usr/hwpf/hwp/pstates/pstates/lab_pstates.h new file mode 100755 index 000000000..5a1b614ca --- /dev/null +++ b/src/usr/hwpf/hwp/pstates/pstates/lab_pstates.h @@ -0,0 +1,101 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hwpf/hwp/pstates/pstates/lab_pstates.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 */ +#ifndef __LAB_PSTATES_H__ +#define __LAB_PSTATES_H__ + +// $Id: lab_pstates.h,v 1.4 2013/06/12 20:01:48 mjjones Exp $ + +/// \file lab_pstates.h +/// \brief Lab-only (as opposed to product-procedure) support for Pstates. + +#include <stdint.h> + +// jwy #include "ssx_io.h" +#include "pstates.h" + +// Error/panic codes + +#define IVID_INVALID_VOLTAGE 0x00484301 +#define PSTATE_STATUS_REPORT_SCOM_ERROR 0x00777701 + +/// String storage requirement for strings used of arguments of +/// sprintf_10uv, sprintf_vrm11() and sprintf_ivid(). +/// +/// \todo Replace with a typedef +#define FORMAT_10UV_STRLEN 8 + +#define FORMAT_10UV_ERROR "<Error>" + +#define ROUND_VOLTAGE_UP 1 +#define ROUND_VOLTAGE_DOWN -1 + +#ifndef __ASSEMBLER__ + +int +vuv2vrm11(uint32_t v_uv, int round, uint8_t *vrm11_vid); + +int +vrm112vuv(uint8_t vrm11_vid, uint32_t *v_uv); + +int +vuv2ivid(uint32_t v_uv, int round, uint8_t *ivid); + +int +ivid2vuv(uint8_t ivid, uint32_t *v_uv); + +int +sprintf_10uv(char *s, uint32_t v_uv); + +int +sprintf_ivid(char *s, uint8_t ivid); + +int +sprintf_vrm11(char *s, uint8_t vrm11); + +#ifdef FAPIECMD + +int +fprintf_10uv(FILE *stream, uint32_t v_uv); + +int +fprintf_vrm11(FILE *stream, uint8_t vrm11); + +int +fprintf_ivid(FILE *stream, uint8_t ivid); + +void +gpst_print(FILE* stream, GlobalPstateTable* gpst); + +void +lpsa_print(FILE* stream, LocalPstateArray* lpsa); + +void +resclk_print(FILE* stream, ResonantClockingSetup* resclk); + +void +pss_print(FILE* stream, PstateSuperStructure* pss); +#endif // FAPIECMD + +#endif // __ASSEMBLER__ + +#endif // __LAB_PSTATES_H__ diff --git a/src/usr/hwpf/hwp/pstates/pstates/p8_build_pstate_datablock.C b/src/usr/hwpf/hwp/pstates/pstates/p8_build_pstate_datablock.C new file mode 100755 index 000000000..ba0d6be88 --- /dev/null +++ b/src/usr/hwpf/hwp/pstates/pstates/p8_build_pstate_datablock.C @@ -0,0 +1,490 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hwpf/hwp/pstates/pstates/p8_build_pstate_datablock.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: p8_build_pstate_datablock.C,v 1.14 2013/06/12 20:05:23 mjjones 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 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//------------------------------------------------------------------------------ +// *! OWNER NAME: Jim Yacynych Email: jimyac@us.ibm.com +// *! + +/// \file p8_build_pstate_datablock.C +/// \brief +/// +/// \todo +/// High-level procedure flow: +/// \verbatim +/// +/// Procedure Prereq: +/// o System clocks are running +/// \endverbatim +//------------------------------------------------------------------------------ + + +// ---------------------------------------------------------------------- +// Includes +// ---------------------------------------------------------------------- +#include <fapi.H> +#include "pstate_tables.h" +#include "lab_pstates.h" +#include "pstates.h" + +#include "p8_build_pstate_datablock.H" + +extern "C" { + +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); +// ---------------------------------------------------------------------- +// Function definitions +// ---------------------------------------------------------------------- +/// \param[in] i_target Chip Target +/// \param[in/out] *io_pss Reference to PstateSuperStructure + +/// \retval FAPI_RC_SUCCESS +/// \retval ERROR defined in xml + +ReturnCode +p8_build_pstate_datablock(const Target& i_target, PstateSuperStructure *io_pss) +{ + fapi::ReturnCode l_rc; + int rc; + + AttributeList attr; + ChipCharacterization* characterization; + uint8_t i = 0; + + double freq_bias = 1.0; + double volt_bias_vdd = 1.0; + double volt_bias_vcs = 1.0; + + 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) + return l_rc; + + // ----------- + // get #V 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; + } + + 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); + 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); + 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 + // ----------------------------------------------- + // Assumes a constant 100mV dead zone + VpdOperatingPoint s132a_vpd[S132A_POINTS]; + + for (i = 0; i < S132A_POINTS; i++) { + s132a_vpd[i].frequency_mhz = attr_mvpd_voltage_control[pv_op_order[i]][0]; + s132a_vpd[i].vdd_5mv = attr_mvpd_voltage_control[pv_op_order[i]][1]; + s132a_vpd[i].idd_500ma = attr_mvpd_voltage_control[pv_op_order[i]][2]; + s132a_vpd[i].vdd_maxreg_5mv = attr_mvpd_voltage_control[pv_op_order[i]][1] - DEAD_ZONE_5MV; + s132a_vpd[i].vcs_5mv = attr_mvpd_voltage_control[pv_op_order[i]][3]; + s132a_vpd[i].ics_500ma = attr_mvpd_voltage_control[pv_op_order[i]][4]; + s132a_vpd[i].vcs_maxreg_5mv = attr_mvpd_voltage_control[pv_op_order[i]][3] - DEAD_ZONE_5MV; + } + + // ------------------------------------------------------------------- + // Create s132a_points and filled in by chip_characterization_create() + // ------------------------------------------------------------------- + OperatingPoint s132a_points[S132A_POINTS]; + + // ------------------------------------------------- + // populate OperatingPointParameters with attributes + // ------------------------------------------------- + // Parameters from a P7 system, consistent with s132a. We'll assume the + // package/header drop is 100uOhm for both Vdd and Vcs. + + OperatingPointParameters s132a_parms; + s132a_parms.pstate0_frequency_khz = s132a_vpd[S132A_POINTS-1].frequency_mhz * 1000; // 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 + + // -------------------------------------- + // Create Chip characterization structure + // -------------------------------------- + + ChipCharacterization s132a_characterization; + s132a_characterization.vpd = s132a_vpd; + s132a_characterization.ops = s132a_points; + s132a_characterization.parameters = &s132a_parms; + s132a_characterization.points = S132A_POINTS; + + // ------------------------------ + // 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 + // --------------------------- + characterization = &s132a_characterization; + + rc = chip_characterization_create(characterization, + characterization->vpd, + characterization->ops, + characterization->parameters, + characterization->points); + + if (rc) { + int & RETURN_CODE = rc; + FAPI_ERR("**** ERROR : Procedure chip_characterization_create() returned %d", rc); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_DATABLOCK_CHIP_CHARACTERIZE_ERROR); + return l_rc; + } + + // ------------------------------ + // 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); + + 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; + 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); + +// Attributes to write +// ------------------- +// uint32_t ATTR_PM_PSTATE0_FREQUENCY // Binary in Khz + + return l_rc; +} + + + +/// \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 l_rc; + + // -------------------------- + // 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 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; + + // ----------------------------------------------------------------- + // get list of chiplets and loop over each and get #V data from each + // ----------------------------------------------------------------- + // check that frequency is the same per chiplet + // for voltage, get the max for use for the chip + + l_rc = fapiGetChildChiplets (i_target, TARGET_TYPE_EX_CHIPLET, l_exChiplets, TARGET_STATE_PRESENT); + if (l_rc) { + FAPI_ERR("Error from fapiGetChildChiplets!"); + return l_rc; + } + + for (j=0; j < l_exChiplets.size(); j++) { + + // Determine if it's functional + l_rc = FAPI_ATTR_GET(ATTR_FUNCTIONAL, &l_exChiplets[j], l_functional); + if (l_rc) { + FAPI_ERR("fapiGetAttribute of ATTR_FUNCTIONAL error"); + return l_rc; + } + else { + + if ( l_functional ) { + l_bufferSize = 512; + uint8_t l_chipNum = 0xFF; + l_rc = FAPI_ATTR_GET(ATTR_CHIP_UNIT_POS, &l_exChiplets[j], l_chipNum); + if (l_rc) { + FAPI_ERR("fapiGetAttribute of ATTR_CHIP_UNIT_POS error"); + return l_rc; + } + + // set l_record to appropriate lprx record (add core number to lrp0) + l_record = (uint32_t)fapi::MVPD_RECORD_LRP0 + l_chipNum; + + // Get Chiplet MVPD data and put in chiplet_mvpd_data using accessor function + l_rc = fapiGetMvpdField((fapi::MvpdRecord)l_record, + fapi::MVPD_KEYWORD_PDV, + i_target, + l_buffer, + l_bufferSize); + if (!l_rc.ok()) { + FAPI_ERR("**** ERROR : Unexpected error encountered in fapiGetMvpdField"); + return l_rc; + } + + // 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); + return l_rc; + } + + // clear array + memset(chiplet_mvpd_data, 0, sizeof(chiplet_mvpd_data)); + + // fill chiplet_mvpd_data 2d array with data iN buffer (skip first byte - bucket id) + #define UINT16_GET(__uint8_ptr) ((uint16_t)( ( (*((const uint8_t *)(__uint8_ptr)) << 8) | *((const uint8_t *)(__uint8_ptr) + 1) ) )) + l_buffer++; + + 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]); + // increment to next MVPD value in buffer + l_buffer+= 2; + } + } + + // on first chiplet put each bucket's data into attr_mvpd_voltage_control + if (first_chplt) { + + for (i=0; i<=4; i++) { + + for (ii=0; ii<=4; ii++) { + attr_mvpd_data[i][ii] = chiplet_mvpd_data[i][ii]; + } + } + first_chplt = 0; + } + else { + // on subsequent chiplets, check that frequencies are same for each bucket for each chiplet + if ( (attr_mvpd_data[0][0] != chiplet_mvpd_data[0][0]) || + (attr_mvpd_data[1][0] != chiplet_mvpd_data[1][0]) || + (attr_mvpd_data[2][0] != chiplet_mvpd_data[2][0]) || + (attr_mvpd_data[3][0] != chiplet_mvpd_data[3][0]) || + (attr_mvpd_data[4][0] != chiplet_mvpd_data[4][0]) ) { + + FAPI_ERR("**** ERROR : Procedure gpst_create() returned "); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_PSTATE_MVPD_CHIPLET_VOLTAGE_NOT_EQUAL); + return l_rc; + } + } + + // check each bucket for max voltage and if max, put bucket's data into attr_mvpd_voltage_control + for (i=0; i <= 4; i++) { + + if (attr_mvpd_data[i][1] < chiplet_mvpd_data[i][1]) { + attr_mvpd_data[i][0] = chiplet_mvpd_data[i][0]; + attr_mvpd_data[i][1] = chiplet_mvpd_data[i][1]; + attr_mvpd_data[i][2] = chiplet_mvpd_data[i][2]; + attr_mvpd_data[i][3] = chiplet_mvpd_data[i][3]; + attr_mvpd_data[i][4] = chiplet_mvpd_data[i][4]; + } + } + } // end if l_functional + else { // Not Functional so skip it + } + } + } // end for loop + + return l_rc; + +} // end proc_get_mvpd_data + + +} //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 new file mode 100755 index 000000000..e883fc819 --- /dev/null +++ b/src/usr/hwpf/hwp/pstates/pstates/p8_build_pstate_datablock.H @@ -0,0 +1,88 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hwpf/hwp/pstates/pstates/p8_build_pstate_datablock.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_build_pstate_datablock.H,v 1.7 2013/05/03 15:57:32 jimyac Exp $ +#ifndef _P8_BUILD_PSTATE_DATABLOCK_H_ +#define _P8_BUILD_PSTATE_DATABLOCK_H_ + +#include <fapi.H> + +// function pointer typedef definition for HWP call support +typedef fapi::ReturnCode (*p8_build_pstate_datablock_FP_t) (const fapi::Target&, PstateSuperStructure*); + +extern "C" { + +//------------------------------------------------------------------------------ +// Function prototype +//------------------------------------------------------------------------------ +/// \brief Build Pstate Tables +/// \param[in] i_target Chip Target +/// \param[in/out] *io_pss Reference to PstateSuperStructure + +fapi::ReturnCode p8_build_pstate_datablock(const fapi::Target& i_target, PstateSuperStructure *io_pss); + +} // extern "C" + +#define S132A_POINTS 3 +#define PSTATE_STEPSIZE 1 +#define EVRM_DELAY_NS 100 +#define DEAD_ZONE_5MV 20 +#define MVPD_BUFFER_SIZE 51 + +// #V 2 dimensional array values (5x5) - 5 operating point and 5 values per operating point +#define PV_D 5 +#define PV_W 5 + +// order of operating points from slow to fast in #V +// 1=pwrsave 0=nominal 2=turbo +const uint8_t pv_op_order[S132A_POINTS] = {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_proc_dpll_divider; // = 4; + + uint32_t attr_freq_bias_up; // = 0; + uint32_t attr_freq_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; + uint32_t attr_voltage_int_bias_down; // = 0; + + 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??? + + 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 + uint32_t attr_pm_resonant_clock_high_band_lower_frequency; // = 0; // Mhz + uint32_t attr_pm_resonant_clock_high_band_upper_frequency; // = 0; // Mhz + +} AttributeList; + +#endif 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 new file mode 100755 index 000000000..04d3585c8 --- /dev/null +++ b/src/usr/hwpf/hwp/pstates/pstates/p8_build_pstate_datablock_errors.xml @@ -0,0 +1,63 @@ +<!-- IBM_PROLOG_BEGIN_TAG --> +<!-- This is an automatically generated prolog. --> +<!-- --> +<!-- $Source: src/usr/hwpf/hwp/pstates/pstates/p8_build_pstate_datablock_errors.xml $ --> +<!-- --> +<!-- 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_build_pstate_datablock_errors.xml,v 1.5 2013/05/03 16:10:11 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> + </hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROCPM_PSTATE_MVPD_CHIPLET_VOLTAGE_NOT_EQUAL</rc> + <description>MVPD Bucket Frequency was not equal per chiplet</description> + </hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROCPM_PSTATE_DATABLOCK_FREQ_BIAS_ERROR</rc> + <description>Cannot have both up and down bias set</description> + </hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROCPM_PSTATE_DATABLOCK_EXT_VOLTAGE_BIAS_ERROR</rc> + <description>Cannot have both up and down bias set</description> + </hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROCPM_PSTATE_DATABLOCK_INT_VOLTAGE_BIAS_ERROR</rc> + <description>Cannot have both up and down bias set</description> + </hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROCPM_PSTATE_DATABLOCK_CHIP_CHARACTERIZE_ERROR</rc> + <description>Procedure chip_characterization_create() returned an error</description> + <ffdc>RETURN_CODE</ffdc> + </hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROCPM_PSTATE_DATABLOCK_GPST_CREATE_ERROR</rc> + <description>Procedure gpst_create() returned an error</description> + <ffdc>RETURN_CODE</ffdc> + </hwpError> +</hwpErrors> diff --git a/src/usr/hwpf/hwp/pstates/pstates/proc_get_voltage.C b/src/usr/hwpf/hwp/pstates/pstates/proc_get_voltage.C new file mode 100755 index 000000000..f3c0631ec --- /dev/null +++ b/src/usr/hwpf/hwp/pstates/pstates/proc_get_voltage.C @@ -0,0 +1,138 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hwpf/hwp/pstates/pstates/proc_get_voltage.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: proc_get_voltage.C,v 1.5 2013/05/02 17:33:30 jimyac Exp $ +// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/ipl/fapi/proc_get_voltage.C,v $ +//------------------------------------------------------------------------------ +// *! (C) Copyright International Business Machines Corp. 2012 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//------------------------------------------------------------------------------ +// *! OWNER NAME: Jim Yacynych Email: jimyac@us.ibm.com +// *! + +/// \file proc_get_voltage.C +/// \brief +/// +/// \todo +/// High-level procedure flow: +/// \verbatim +/// +/// Procedure Prereq: +/// o System clocks are running +/// \endverbatim +//------------------------------------------------------------------------------ + +// ---------------------------------------------------------------------- +// Includes +// ---------------------------------------------------------------------- +#include <fapi.H> + +#include "pstate_tables.h" +#include "lab_pstates.h" +#include "pstates.h" + +#include "proc_get_voltage.H" + +extern "C" { + +using namespace fapi; + +// ---------------------------------------------------------------------- +// Function prototypes +// ---------------------------------------------------------------------- +//ReturnCode freq2pState(uint32_t freq, PstateSuperStructure *pss, int32_t& pstate); + +// ---------------------------------------------------------------------- +// Function definitions +// ---------------------------------------------------------------------- +/// \param[in] i_target Chip Target +/// \param[in] i_freq_mhz frequency in Mhz +/// \param[out] *o_vdd_vid vdd vid value +/// \param[out] *o_vcs_vid vcs vid value + +/// \retval FAPI_RC_SUCCESS +/// \retval ERROR defined in xml + +ReturnCode +proc_get_voltage(const Target& i_target, const uint32_t i_freq_mhz, uint8_t& o_vdd_vid, uint8_t& o_vcs_vid) +{ + fapi::ReturnCode l_rc; + int rc = 0; + PstateSuperStructure pss; + gpst_entry_t entry; + Pstate freq_pstate = 0; + Pstate pmax = 0; + uint8_t freq_pstate_index = 0; + + // ----------------------------- + // create pstate super structure + // ----------------------------- + FAPI_INF("Executing p8_build_pstate_datablock"); + + FAPI_EXEC_HWP(l_rc, p8_build_pstate_datablock, i_target, &pss); + if (!l_rc.ok()) { + FAPI_ERR("Error calling p8_build_pstate_datablock"); + return l_rc; + } + + // ---------------------- + // convert freq to pstate + // ---------------------- + rc = freq2pState(&(pss.gpst), (i_freq_mhz*1000), &freq_pstate); + + if (rc) { + int & RETURN_CODE = rc; + FAPI_ERR("**** ERROR : Procedure freq2pState() returned %d", rc); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_GET_VOLTAGE_FREQ2PSTATE_ERROR); + return l_rc; + } + + // ---------------------- + // pstate bounds checking + // ---------------------- + pmax = pss.gpst.pmin + pss.gpst.entries - 1; + + FAPI_DBG("freq_pstate = %d pmax = %d pmin = %d entries = %d i_freq_mhz = %d\n", freq_pstate, pmax, pss.gpst.pmin, pss.gpst.entries, i_freq_mhz); + + if (freq_pstate > pmax) { + FAPI_ERR("**** ERROR : Pstate for given frequency is greater than pmax %d > %d (pmax)", freq_pstate, pmax); + FAPI_SET_HWP_ERROR(l_rc, RC_PROCPM_GET_VOLTAGE_FREQ_PSTATE_GT_PMAX_ERROR); + return l_rc; + } + + if (freq_pstate < pss.gpst.pmin) { + freq_pstate = pss.gpst.pmin; + } + + // -------------------------------------------------------- + // convert pstate to pstate table index and lookup voltages + // -------------------------------------------------------- + freq_pstate_index = freq_pstate - pss.gpst.pmin; + entry.value = revle64(pss.gpst.pstate[freq_pstate_index].value); + o_vdd_vid = entry.fields.evid_vdd; + o_vcs_vid = entry.fields.evid_vcs; + return l_rc; +} + +} //end extern C + diff --git a/src/usr/hwpf/hwp/pstates/pstates/proc_get_voltage.H b/src/usr/hwpf/hwp/pstates/pstates/proc_get_voltage.H new file mode 100755 index 000000000..737e58d5f --- /dev/null +++ b/src/usr/hwpf/hwp/pstates/pstates/proc_get_voltage.H @@ -0,0 +1,49 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hwpf/hwp/pstates/pstates/proc_get_voltage.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: proc_get_voltage.H,v 1.3 2012/12/10 19:28:57 jimyac Exp $ +// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/ipl/fapi/proc_get_voltage.H,v $ +#ifndef _proc_get_voltage_H_ +#define _proc_get_voltage_H_ + +#include <fapi.H> +#include "p8_build_pstate_datablock.H" + +// function pointer typedef definition for HWP call support +typedef fapi::ReturnCode (*proc_get_voltage_FP_t) (const fapi::Target&,const uint32_t, uint8_t &, uint8_t &); + +extern "C" { + +//------------------------------------------------------------------------------ +// Function prototype +//------------------------------------------------------------------------------ +/// \brief Build Pstate Tables +/// \param[in] i_target Chip Target +/// \param[in] i_freq_mhz frequency in Mhz +/// \param[out] o_vdd_vid vdd value for given frequency +/// \param[out] o_vcs_vid vcs value for given frequency + +fapi::ReturnCode proc_get_voltage(const fapi::Target& i_target, const uint32_t i_freq_mhz, uint8_t& o_vdd_vid, uint8_t& o_vcs_vid); + +} // extern "C" + +#endif diff --git a/src/usr/hwpf/hwp/pstates/pstates/proc_get_voltage_errors.xml b/src/usr/hwpf/hwp/pstates/pstates/proc_get_voltage_errors.xml new file mode 100755 index 000000000..f74331a2b --- /dev/null +++ b/src/usr/hwpf/hwp/pstates/pstates/proc_get_voltage_errors.xml @@ -0,0 +1,37 @@ +<!-- IBM_PROLOG_BEGIN_TAG --> +<!-- This is an automatically generated prolog. --> +<!-- --> +<!-- $Source: src/usr/hwpf/hwp/pstates/pstates/proc_get_voltage_errors.xml $ --> +<!-- --> +<!-- 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: proc_get_voltage_errors.xml,v 1.5 2013/05/03 16:10:12 jimyac Exp $ --> +<!-- Error definitions for proc_get_voltage procedure --> +<hwpErrors> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROCPM_GET_VOLTAGE_FREQ_PSTATE_GT_PMAX_ERROR</rc> + <description>Pstate for given frequency is greater than pmax</description> + </hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROCPM_GET_VOLTAGE_FREQ2PSTATE_ERROR</rc> + <description>Procedure freq2pState() returned an error</description> + <ffdc>RETURN_CODE</ffdc> + </hwpError> +</hwpErrors> diff --git a/src/usr/hwpf/hwp/pstates/pstates/pstate_tables.c b/src/usr/hwpf/hwp/pstates/pstates/pstate_tables.c new file mode 100755 index 000000000..5212b1a76 --- /dev/null +++ b/src/usr/hwpf/hwp/pstates/pstates/pstate_tables.c @@ -0,0 +1,716 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hwpf/hwp/pstates/pstates/pstate_tables.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: pstate_tables.c,v 1.8 2013/06/12 20:02:07 mjjones Exp $ + +/// \file pstate_tables.c +/// \brief This file contains code used to generate Pstate tables from real or +/// imagined chip characterizations. +/// +/// This code is never run as part of OCC firmware, as Pstate tables are +/// always "given" to OCC either from the FSP (OCC product firmware), or by +/// being built-in the image (lab images). + +#include <stdint.h> +#include <stdio.h> +#include "lab_pstates.h" +#include "pstate_tables.h" + + +#define MAX(X, Y) \ + ({ \ + typeof (X) __x = (X); \ + typeof (Y) __y = (Y); \ + (__x > __y) ? __x : __y; \ + }) + +static int +cntlz32(uint32_t x) +{ + return __builtin_clz(x); +} + + +/// Byte-reverse a 16-bit integer if on a little-endian machine + +uint16_t +revle16(uint16_t i_x) +{ + uint16_t rx; + +#ifndef _BIG_ENDIAN + uint8_t *pix = (uint8_t*)(&i_x); + uint8_t *prx = (uint8_t*)(&rx); + + prx[0] = pix[1]; + prx[1] = pix[0]; +#else + rx = i_x; +#endif + + return rx; +} + + +/// Byte-reverse a 32-bit integer if on a little-endian machine + +uint32_t +revle32(uint32_t i_x) +{ + uint32_t rx; + +#ifndef _BIG_ENDIAN + uint8_t *pix = (uint8_t*)(&i_x); + uint8_t *prx = (uint8_t*)(&rx); + + prx[0] = pix[3]; + prx[1] = pix[2]; + prx[2] = pix[1]; + prx[3] = pix[0]; +#else + rx = i_x; +#endif + + return rx; +} + + +/// Byte-reverse a 64-bit integer if on a little-endian machine + +uint64_t +revle64(const uint64_t i_x) +{ + uint64_t rx; + +#ifndef _BIG_ENDIAN + uint8_t *pix = (uint8_t*)(&i_x); + uint8_t *prx = (uint8_t*)(&rx); + + prx[0] = pix[7]; + prx[1] = pix[6]; + prx[2] = pix[5]; + prx[3] = pix[4]; + prx[4] = pix[3]; + prx[5] = pix[2]; + prx[6] = pix[1]; + prx[7] = pix[0]; +#else + rx = i_x; +#endif + + return rx; +} + +/// Create a ChipCharacterization from an array of VPD operating points and +/// characterization parameters. +/// +/// \param characterization An uninitialized or unused ChipCharacterization +/// structure. +/// +/// \param vpd An initialized array of VpdOperatingPoints, sorted by increasing +/// frequency. Note that there must be at least 1 DPLL frequency code step (1 +/// Pstate step) between each VPD operating point in order to use the +/// characterization to create a Pstate table. +/// +/// \param ops An uninitialized array of OperatingPoint, this array will be +/// intialized by this API. +/// +/// \param parameters An initialized OperatingPointParameters structure +/// +/// \param points The (non-negative) number of operating points +/// +/// \retval 0 Success +/// +/// \returns Other return codes indicate errors. + +int +chip_characterization_create(ChipCharacterization *characterization, + VpdOperatingPoint *vpd, + OperatingPoint *ops, + OperatingPointParameters *parameters, + int points) +{ + int rc, i; + uint32_t pstate0_code; + uint8_t gpst_points = 0; // jwy + uint32_t curr_pstate_code = 0; // jwy + uint32_t next_pstate_code = 0; // jwy + + + do { + rc = 0; + + if ((characterization == 0) || (parameters == 0)) { + rc = -GPST_INVALID_OBJECT; + break; + } + if ((vpd == 0) || (points <= 0)) { + rc = -GPST_INVALID_ARGUMENT; + break; + } + + characterization->vpd = vpd; + characterization->ops = ops; + characterization->parameters = parameters; + characterization->points = points; + + // Now convert the array of VPD operating point to the array of + // internal operating points + // + // For frequencies and characterization voltages and currents this is + // simple math. Creating load-line corrected volatges requires + // multiplying worst-case currents by the effective load-line + // resistance. + // + // Note that the Pstate computation is made relative to the Pstate 0 + // frequency code (DPLL input). It's done this way so that + // frequencies with non-integral codes always round down (to lower + // frequencies). + + pstate0_code = + parameters->pstate0_frequency_khz / parameters->frequency_step_khz; + + for (i = 0; i < points; i++) { + + // jwy skip vpd point if next point is at same pstate + curr_pstate_code = vpd[i].frequency_mhz * 1000 / parameters->frequency_step_khz; + if (i < points - 1) { + next_pstate_code = vpd[i+1].frequency_mhz * 1000 / parameters->frequency_step_khz; + } + + if (i < points - 1 && (curr_pstate_code == next_pstate_code)) { + continue; + } + + ops[gpst_points].vdd_uv = vpd[i].vdd_5mv * 5000; + ops[gpst_points].vcs_uv = vpd[i].vcs_5mv * 5000; + + ops[gpst_points].vdd_maxreg_uv = vpd[i].vdd_maxreg_5mv * 5000; + ops[gpst_points].vcs_maxreg_uv = vpd[i].vcs_maxreg_5mv * 5000; + + 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 + + ops[gpst_points].vdd_corrected_uv = + ops[gpst_points].vdd_uv + + ((ops[gpst_points].idd_ma * (parameters->vdd_load_line_uohm + parameters->vdd_distribution_uohm)) / 1000); // jwy add in distribution_uohm + + ops[gpst_points].vcs_corrected_uv = + ops[gpst_points].vcs_uv + + ((ops[gpst_points].ics_ma * (parameters->vcs_load_line_uohm + parameters->vcs_distribution_uohm)) / 1000); // jwy add in distribution_uohm + + // iVRM 'Effective' voltages are set to the measured voltages + + ops[gpst_points].vdd_ivrm_effective_uv = ops[gpst_points].vdd_uv; + ops[gpst_points].vcs_ivrm_effective_uv = ops[gpst_points].vcs_uv; + + ops[gpst_points].pstate = + (ops[gpst_points].frequency_khz / parameters->frequency_step_khz) - + pstate0_code; + + gpst_points++; + } + + // jwy set points to adjusted number of points (ie. if vpd point was skipped due to being same pstate + // jwy as next vpd point + characterization->points = gpst_points; + + } while (0); + + return rc; +} + + +// Set up GPST Pstate stepping parameters +// +// \param gpst A GlobalPstateTable object to be initialized with the stepping +// setup. +// +// \param pstate_stepsize Unsigned 7 bit (baby-) stepsize for Pstate +// transitions between the Global Pstate Actual and the Global Pstate +// Target. The value 0 is considered illegal here. +// +// \param vrm_delay_ns This value defines the voltage settling delay (in +// nano-seconds) after each voltage change sequenced by the GPSM. This +// includes all voltage changes \e except those explicitly managed by +// firmware manipulation of the SPIVID interface. Legal values range from 0 +// up to approximately 1,600,000 (1.6ms). The VRM step delay is stored using +// an exponential encoding. The step delay computed here is a +// normalized (if possible) exponential encoding for highest accuracy. +// +// \note The caller is responsible for the mode-correctness of this call. +// The call should only be made when the GPSM is quiesced. +// +// \retval 0 Success +// +// \retval -GPST_INVALID_ARGUMENT Either argument was invalid in some way. + +#define NEST_FREQUENCY_KHZ 2400000 + +int +gpst_stepping_setup(GlobalPstateTable* gpst, + int pstate_stepsize, + int vrm_delay_ns) +{ + uint32_t cycles; + int rc, sigbits, stepdelay_range, stepdelay_value; + + do { + rc = 0; + + if ((pstate_stepsize <= 0) || + (pstate_stepsize > PSTATE_STEPSIZE_MAX) || + (vrm_delay_ns < 0) || + (vrm_delay_ns > VRM_STEPDELAY_MAX)) { + rc = -GPST_INVALID_ARGUMENT; + break; + } + + // Compute the number of pervasive / 2 cycles implied by the delay. + // 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) / + (1 << LOG2_VRM_STEPDELAY_DIVIDER); + + // Normalize the exponential encoding + + sigbits = 32 - cntlz32(cycles); + stepdelay_range = (sigbits - VRM_STEPDELAY_RANGE_BITS); + + if (stepdelay_range < 0) + { + stepdelay_range = 0; + } + + stepdelay_value = cycles >> (stepdelay_range + LOG2_VRM_STEPDELAY_DIVIDER); + + if (stepdelay_range > ((1u << VRM_STEPDELAY_RANGE_BITS) - 1)) { + rc = -GPST_INVALID_ARGUMENT; + break; + } + + gpst->pstate_stepsize = pstate_stepsize; + gpst->vrm_stepdelay_range = stepdelay_range; + gpst->vrm_stepdelay_value = stepdelay_value; + + } while (0); + + return rc; +} + + +// Create (initialize) a GPST entry from an operating point. +// +// Most of the voltages are straightforward - note that vuv2vrm11 rounds the +// voltages safely. +// +// The specification requires that Vcs be given as a signed offset. The Vcs +// offset is a simple signed number of VID steps (not a crazy inverted +// encoding like the Vdd VID code). We're always going to round the VCS offset +// up (greater Vdiff). A fine point - we add the original offset to the +// VRM-11 form of the voltage, not the original voltage, further potentially +// increasing Vdiff. +// +// -*- NB : Note a subtle point about endianess here: The gpst_entry_t is +// coded to allow the correct creation of the uint64_t form of the object on +// big/little endian machines. However, the 'gpe' pointer here is a pointer +// to a structure in a memory image, and using the host-endian form of the +// structure is wrong - in this case we always need to use the big-endian +// form! So we first construct the entry as an integer, then reverse it into +// the image. + +static int +gpst_entry_create(gpst_entry_t *entry, OperatingPoint *op) +{ + int rc; + uint8_t vid; +// jwy int32_t vcs_offset; +// jwy uint32_t vdd_uv; + gpst_entry_t gpe; + + do { + + // Clear the entry and do the straightforward conversions + + gpe.value = 0; + +#define __SET(type, round, gpe_field, op_field) \ + rc = vuv2##type(op->op_field, round, &vid); \ + if (rc) break; \ + gpe.fields.gpe_field = vid; + + __SET(vrm11, ROUND_VOLTAGE_UP, evid_vdd, vdd_corrected_uv); + __SET(vrm11, ROUND_VOLTAGE_UP, evid_vcs, vcs_corrected_uv); + __SET(ivid, ROUND_VOLTAGE_DOWN, evid_vdd_eff, vdd_ivrm_effective_uv); + __SET(ivid, ROUND_VOLTAGE_DOWN, evid_vcs_eff, vcs_ivrm_effective_uv); + __SET(ivid, ROUND_VOLTAGE_DOWN, maxreg_vdd, vdd_maxreg_uv); + __SET(ivid, ROUND_VOLTAGE_DOWN, maxreg_vcs, vcs_maxreg_uv); + + // Add the check byte + + uint8_t gpstCheckByte(uint64_t gpstEntry); + gpe.fields.ecc = gpstCheckByte(gpe.value); + + } while (0); + + // Byte reverse the entry into the image. + + entry->value = revle64(gpe.value); + return rc; +} + + +// Linear interpolation of voltages + +static uint32_t +interpolate(uint32_t base, uint32_t next, int step, int steps) +{ + return base + (((next - base) * step) / steps); +} + + +/// Create a global Pstate table from an array of internal operating points +/// +/// \param gpst A pointer to a GlobalPstateTable structure. This structure +/// must not currently be in use as the PMC Global Pstate Table. +/// +/// \param characterization An initialized ChipCharacterization. The +/// operating point table must be sorted in ascending order by both Pstate and +/// (uncorrected) Vdd and Vcs voltages. The range of Pstates in the table must +/// also physicaly fit within the physical number of entries. +/// +/// \param pstate_stepsize Pstate step size +/// +/// \param evrm_delay_ns External VRM delay in nano-seconds +/// +/// This routine creates a GlobalPstateTable by linear interpolation of +/// corrected voltages between characterized operating points. +/// +/// Defaults - Can be overidden later: +/// +/// - The Psafe is always set to the minimum Pstate +/// - The dpll_fmax_bias is set to 0 for all cores +/// - The undervolting bias is set to 0 +/// - The pstate0_frequency_code is det to the default value for all cores. +/// +/// This routine always checks for errors +/// +/// \retval 0 Success +/// +/// \retval -GPST_INVALID_OBJECT Either the \a gpst or \a ops were NULL (0) or +/// obviously invalid or incorrectly initialized. +/// +/// \retval -GPST_INVALID_ARGUMENT This code indicates one of several types of +/// errors that may occur in the \a ops. +/// +/// \retval -VRM_INVALID_VOLTAGE A characterized or interpolated voltage can +/// not be represented as a VRM-11 VID code. + +int +gpst_create(GlobalPstateTable *gpst, + ChipCharacterization *characterization, + int pstate_stepsize, + int evrm_delay_ns) +{ + OperatingPoint *ops, interp; + int rc, points, i, entry, pstate; + int32_t pmin, pmax; + uint8_t fNom; + + do { + rc = 0; + + // Basic pointer checks + + if ((gpst == 0) || (characterization == 0)) { + rc = -GPST_INVALID_OBJECT; + break; + } + + // Check for null or illegal operating point tables + + ops = characterization->ops; + points = characterization->points; + + if ((ops == 0) || (points <= 0)) { + rc = -GPST_INVALID_OBJECT; + break; + } + + pmin = ops[0].pstate; + pmax = ops[points - 1].pstate; + + // Check that the range of Pstates are legal and will actually fit in + // the table. 'Fitting' will never be a problem for PgP as long as the + // table of operating points does not include operating points for + // frequencies below Fmax@Vmin. + + if ((pmin < PSTATE_MIN) || + (pmax > PSTATE_MAX) || + ((pmax - pmin + 1) > GLOBAL_PSTATE_TABLE_ENTRIES)) { + rc = -GPST_INVALID_ARGUMENT; + break; + } + + // Check the ordering constraints + + for (i = 1; i < points; i++) { + + if ((ops[i].pstate < ops[i - 1].pstate) || + (ops[i].vdd_uv < ops[i - 1].vdd_uv) || // jwy allow them to be equal + (ops[i].vcs_uv < ops[i - 1].vcs_uv)) { // jwy allow them to be equal + rc = -GPST_INVALID_ARGUMENT; + break; + } + } + if (rc) break; + + // Update the table from VPD/system parameters, then default the + // pstate0_frequency_code (fNom) to the 'nominal' code and set the + // DPLL bias to 0. + + gpst->pstate0_frequency_khz = + revle32(characterization->parameters->pstate0_frequency_khz); + gpst->frequency_step_khz = + revle32(characterization->parameters->frequency_step_khz); + + // Now we can interpolate the operating points to build the + // table. Interpolation is done by creating (or using) an + // OperatingPoint for each intermediate (or characterized) Pstate. + // The gpst_entry_create() function then creates the GPST entry from + // the operating point. Only the voltages are interpolated, and they + // are all interpolated in units of micro-Volts. + + gpst->pmin = pmin; + gpst->entries = pmax - pmin + 1; + + // Set the Pmin Pstate + + entry = 0; + if (gpst_entry_create(&(gpst->pstate[entry]), &(ops[0]))) { + rc = -GPST_INVALID_ENTRY; + break; + } + entry++; + pstate = pmin; + + // Iterate over characterized operating points... + for (i = 1; i < points; i++) { + + // Interpolate intermediate Pstates... + while (++pstate != ops[i].pstate) { + + interp.pstate = pstate; + +#define __INTERPOLATE(field) \ + do { \ + interp.field = \ + interpolate(ops[i - 1].field, ops[i].field, \ + (pstate - ops[i - 1].pstate), \ + (ops[i].pstate - ops[i - 1].pstate)); \ + } while (0) + + __INTERPOLATE(vdd_corrected_uv); + __INTERPOLATE(vcs_corrected_uv); + __INTERPOLATE(vdd_ivrm_effective_uv); + __INTERPOLATE(vcs_ivrm_effective_uv); + __INTERPOLATE(vdd_maxreg_uv); + __INTERPOLATE(vcs_maxreg_uv); + + if (gpst_entry_create(&(gpst->pstate[entry]), &interp)) { + rc = - GPST_INVALID_ENTRY; + break; + } + entry++; + } + if (rc) break; + + // Set the characterized Pstate + if (gpst_entry_create(&(gpst->pstate[entry]), &(ops[i]))) { + rc = -GPST_INVALID_ENTRY; + break; + } + entry++; + } + if (rc) break; + + // Fill in the defaults + + gpst->pvsafe = gpst->pmin; + + fNom = revle32(gpst->pstate0_frequency_khz) / + revle32(gpst->frequency_step_khz); + + for (i = 0; i < PGP_NCORES; i++) { + gpst->pstate0_frequency_code[i] = revle16(fNom); + gpst->dpll_fmax_bias[i] = 0; + } + + } while (0); + + return rc; +} + + + +int +lpst_create(const GlobalPstateTable *gpst, LocalPstateArray *lpsa, const uint8_t dead_zone_5mv) +{ + int rc = 0; + int i,j; + gpst_entry_t entry; + uint32_t turbo_uv; + uint32_t v_uv; + uint32_t vdd_uv; + uint8_t v_ivid; + uint32_t lpst_max_uv; + uint8_t lpst_entries; + uint8_t lpst_entries_div4; + uint8_t gpst_index; + Pstate lpst_pmin; + uint8_t vid_incr[3] = {0,0,0}; + + do { + + // Basic pointer checks + if (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); + 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); + + if (lpst_max_uv >= v_uv) + 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); + + // ---------------------------------------------------------------------------- + // now loop over gpst from 0 to lpst_entries and fill in lpst from data in gpst + // ---------------------------------------------------------------------------- + gpst_index = 0; + + lpst_entries_div4 = lpst_entries/4; + if ( lpst_entries % 4 != 0) + lpst_entries_div4++; + + 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); + 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); + lpsa->pstate[i].fields.ivid_vcs = v_ivid; + + // -------------------------------------------------------------- + // compute increment for remaining 3 pstates for this lpst entry + // -------------------------------------------------------------- + vid_incr[0] = 0; + vid_incr[1] = 0; + vid_incr[2] = 0; + + for (j = 0; j <= 2; j++) { + gpst_index++; + if (gpst_index > lpst_entries) + break; + + 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); + vid_incr[j] = v_ivid - lpsa->pstate[i].fields.ivid_vdd; + } + + lpsa->pstate[i].fields.ps1_vid_incr = vid_incr[0]; + lpsa->pstate[i].fields.ps2_vid_incr = vid_incr[1]; + lpsa->pstate[i].fields.ps3_vid_incr = vid_incr[2]; + + // -------------------- + // compute power ratios + // -------------------- + float sigma = 0; + float iac_wc; + float iac; + float vout; + float pwrratio_f; + uint8_t pwrratio; + + // convert to mV (note: vdd_uv is the max of the vdd values for this lpst entry) + vout = (float)(vdd_uv/1000); + + // equations from Josh + iac_wc = 1.25 * ( 28.5 * 1.25 - 16 ) * ( 1 - 0.05 * 2) * 40/71; // testsite equation & ratio of testsite to anticipated produ + iac = 1.25 * (-15.78 -0.618 * sigma + 27.6 * vout/1000) * 40/64; // product equation & ratio of testsite to actual product + pwrratio_f = iac / iac_wc; + 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; + + // ??? what should these be ??? set to 1 for now + lpsa->pstate[i].fields.inc_step = 1; + lpsa->pstate[i].fields.dec_step = 1; + +// 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]); + + // Byte reverse the entry into the image. + lpsa->pstate[i].value = revle64(lpsa->pstate[i].value); + + gpst_index++; + if (gpst_index > lpst_entries) + break; + } + + // set these fields in lpst structure + lpsa->pmin = lpst_pmin; + lpsa->entries = lpst_entries; + + } while (0); + + return rc; + +} // end lpst_create diff --git a/src/usr/hwpf/hwp/pstates/pstates/pstate_tables.h b/src/usr/hwpf/hwp/pstates/pstates/pstate_tables.h new file mode 100755 index 000000000..f4dd6b275 --- /dev/null +++ b/src/usr/hwpf/hwp/pstates/pstates/pstate_tables.h @@ -0,0 +1,157 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hwpf/hwp/pstates/pstates/pstate_tables.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 */ +#ifndef __PSTATE_TABLES_H__ +#define __PSTATE_TABLES_H__ + +// $Id: pstate_tables.h,v 1.6 2013/05/02 17:33:31 jimyac Exp $ + +/// \file pstate_tables.h +/// \brief Code used to generate Pstate tables from real or imagined chip +/// characterizations. + +#include "pstates.h" + +// Constants associated with VRM stepping + +#define PSTATE_STEPSIZE_MAX 127 +#define VRM_STEPDELAY_RANGE_BITS 4 +#define LOG2_VRM_STEPDELAY_DIVIDER 3 +#define VRM_STEPDELAY_MAX 1600000 + + +#ifndef __ASSEMBLER__ + +/// A VPD operating point +/// +/// VPD operating points are stored without load-line correction. Frequencies +/// are in MHz, voltages are specified in units of 5mV, and characterization +/// currents are specified in units of 500mA. +/// +/// \bug The assumption is that the 'maxreg' points for the iVRM will also be +/// supplied in the VPD in units of 5mv. If they are supplied in some other +/// form then chip_characterization_create() will need to be modified. + +typedef struct { + + uint32_t vdd_5mv; + uint32_t vcs_5mv; + uint32_t vdd_maxreg_5mv; + uint32_t vcs_maxreg_5mv; + uint32_t idd_500ma; + uint32_t ics_500ma; + uint32_t frequency_mhz; + +} VpdOperatingPoint; + + +/// An internal operating point +/// +/// Internal operating points include characterization and load-line corrected +/// voltages for the external VRM. For the internal VRM, effective e-voltages +/// and maxreg voltages are stored. All voltages are stored as +/// uV. Characterization currents are in mA. Frequencies are in KHz. The +/// Pstate of the operating point (as a potentially out-of-bounds value) is +/// also stored. + +typedef struct { + + uint32_t vdd_uv; + uint32_t vcs_uv; + uint32_t vdd_corrected_uv; + uint32_t vcs_corrected_uv; + uint32_t vdd_ivrm_effective_uv; + uint32_t vcs_ivrm_effective_uv; + uint32_t vdd_maxreg_uv; + uint32_t vcs_maxreg_uv; + uint32_t idd_ma; + uint32_t ics_ma; + uint32_t frequency_khz; + int32_t pstate; + +} OperatingPoint; + + +/// Constants required to compute and interpolate operating points +/// +/// The nominal frequency and frequency step-size is given in Hz. Load-line +/// and on-chip distribution resistances are given in micro-Ohms. +/// +/// \todo Confirm that the "eVID V[dd,cs] Eff" correction is modeled as a simple +/// resistance similar to the load line. + +typedef struct { + + uint32_t pstate0_frequency_khz; + uint32_t frequency_step_khz; + uint32_t vdd_load_line_uohm; + uint32_t vcs_load_line_uohm; + uint32_t vdd_distribution_uohm; + uint32_t vcs_distribution_uohm; + +} OperatingPointParameters; + + +/// A chip characterization + +typedef struct { + + VpdOperatingPoint *vpd; + OperatingPoint *ops; + OperatingPointParameters *parameters; + int points; + +} ChipCharacterization; + + +uint16_t +revle16(uint16_t i_x); + +uint32_t +revle32(uint32_t x); + +uint64_t +revle64(const uint64_t i_x); + +int +chip_characterization_create(ChipCharacterization *characterization, + VpdOperatingPoint *vpd, + OperatingPoint *ops, + OperatingPointParameters *parameters, + int points); + +int +gpst_create(GlobalPstateTable *gpst, + ChipCharacterization *characterization, + int pstate_stepsize, + int evrm_delay_ns); + + +int +lpst_create(const GlobalPstateTable *gpst, + LocalPstateArray *lpsa, + const uint8_t dead_zone_5mv); + + +#endif // __ASSEMBLER__ + +#endif // __PSTATE_TABLES_H__ 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; +} diff --git a/src/usr/hwpf/hwp/pstates/pstates/pstates.h b/src/usr/hwpf/hwp/pstates/pstates/pstates.h new file mode 100755 index 000000000..b0f8e77d4 --- /dev/null +++ b/src/usr/hwpf/hwp/pstates/pstates/pstates.h @@ -0,0 +1,512 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hwpf/hwp/pstates/pstates/pstates.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 */ +#ifndef __PSTATES_H__ +#define __PSTATES_H__ + +// $Id: pstates.h,v 1.6 2013/05/02 17:33:33 jimyac Exp $ + +/// \file pstates.h +/// \brief Pstate structures and support routines for OCC product firmware + +#include "pgp_common.h" + +//////////////////////////////////////////////////////////////////////////// +// Global and Local Pstate Tables +//////////////////////////////////////////////////////////////////////////// + +/// The Global Pstate Table must be 1KB-aligned in SRAM. The alignment is +/// specified in the traditional log2 form. +#define GLOBAL_PSTATE_TABLE_ALIGNMENT 10 + +/// 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 VRM-11 VID base voltage in micro-Volts +#define VRM11_BASE_UV 1612500 + +/// The VRM-11 VID step as an unsigned number (micro-Volts) +#define VRM11_STEP_UV 6250 + +/// The iVID base voltage in micro-Volts +#define IVID_BASE_UV 600000 + +/// The iVID step as an unsigned number (micro-Volts) +#define IVID_STEP_UV 6250 + +// Error/Panic codes for support routines + +#define VRM11_INVALID_VOLTAGE 0x00876101 + +#define PSTATE_OVERFLOW 0x00778a01 +#define PSTATE_UNDERFLOW 0x00778a02 + +#define PSTATE_LT_PSTATE_MIN 0x00778a03 +#define PSTATE_GT_PSTATE_MAX 0x00778a04 + +#define DPLL_OVERFLOW 0x00d75501 +#define DPLL_UNDERFLOW 0x00d75502 + +#define VID11_OVERFLOW 0x00843101 +#define VID11_UNDERFLOW 0x00843102 + +#define GPST_INVALID_OBJECT 0x00477801 +#define GPST_INVALID_ARGUMENT 0x00477802 +#define GPST_INVALID_ENTRY 0x00477803 +#define GPST_PSTATE_CLIPPED_LOW 0x00477804 +#define GPST_PSTATE_CLIPPED_HIGH 0x00477805 +#define GPST_BUG 0x00477806 + +#define LPST_INVALID_OBJECT 0x00477901 + + + +/// PstateSuperStructure Magic Number +/// +/// This magic number identifies a particular version of the +/// PstateSuperStructure and its substructures. The version number should be +/// kept up to date as changes are made to the layout or contents of the +/// structure. + +#define PSTATE_SUPERSTRUCTURE_MAGIC 0x5053544154453031ull /* PSTATE01 */ + + +/// \defgroup pstate_options Pstate Options +/// +/// These are flag bits for the \a options field of the PstateOptions +/// structure. +/// +/// @{ + +/// gpsm_gpst_install() - Bypass copying the Pstate table from the +/// PstateSuperStructure into the aligned global location. +#define PSTATE_NO_COPY_GPST 0x01 + +/// gpsm_gpst_install() - Bypass Global Pstate Table installation and setup. +#define PSTATE_NO_INSTALL_GPST 0x02 + +/// gpsm_lpsa_install() - Bylass Local Pstate Array installation and setup +#define PSTATE_NO_INSTALL_LPSA 0x04 + +/// gpsm_resclk_install - Bypass resonant clocking Pstate limit setup +#define PSTATE_NO_INSTALL_RESCLK 0x08 + +/// gpsm_enable_pstates() - Force the system to the minimum Pstate at +/// initialization +/// +/// This mode is added as a workaround for the case that the SPIVID interface +/// is not working correctly during initial bringup. This forces Pstate mode +/// to come up at a low frequency. +#define PSTATE_FORCE_INITIAL_PMIN 0x10 + +/// @} + +#ifndef __ASSEMBLER__ + +#include <stdint.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 +/// in procedures that do 'manual' Pstate manipulation. + +typedef union gpst_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 evid_vdd : 8; + uint64_t evid_vcs : 8; + uint64_t reserved16 : 1; + uint64_t evid_vdd_eff : 7; + uint64_t reserved24 : 1; + uint64_t evid_vcs_eff : 7; + uint64_t reserved32 : 1; + uint64_t maxreg_vdd : 7; + uint64_t reserved40 : 1; + uint64_t maxreg_vcs : 7; + uint64_t reserved48 : 8; + uint64_t ecc : 8; +#else + uint64_t ecc : 8; + uint64_t reserved48 : 8; + uint64_t maxreg_vcs : 7; + uint64_t reserved40 : 1; + uint64_t maxreg_vdd : 7; + uint64_t reserved32 : 1; + uint64_t evid_vcs_eff : 7; + uint64_t reserved24 : 1; + uint64_t evid_vdd_eff : 7; + uint64_t reserved16 : 1; + uint64_t evid_vcs : 8; + uint64_t evid_vdd : 8; +#endif // _BIG_ENDIAN + } fields; + +} gpst_entry_t; + + +/// A Local Pstate Table Entry, in the form of a packed 'firmware register' +/// +/// This structure is provided for reference only; Currently the OCC firmware +/// does not manupulate Local Pstate table entries, however it is possible +/// that future lab applications will require this. + +typedef union lpst_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 ivid_vdd : 7; + uint64_t ivid_vcs : 7; + uint64_t vdd_core_pwrratio : 6; + uint64_t vcs_core_pwrratio : 6; + uint64_t vdd_eco_pwrratio : 6; + uint64_t vcs_eco_pwrratio : 6; + uint64_t ps1_vid_incr : 3; + uint64_t ps2_vid_incr : 3; + uint64_t ps3_vid_incr : 3; + uint64_t reserved47 : 7; + uint64_t inc_step : 3; + uint64_t dec_step : 3; + uint64_t reserved60 : 4; +#else + uint64_t reserved60 : 4; + uint64_t dec_step : 3; + uint64_t inc_step : 3; + uint64_t reserved47 : 7; + uint64_t ps3_vid_incr : 3; + uint64_t ps2_vid_incr : 3; + uint64_t ps1_vid_incr : 3; + uint64_t vcs_eco_pwrratio : 6; + uint64_t vdd_eco_pwrratio : 6; + uint64_t vcs_core_pwrratio : 6; + uint64_t vdd_core_pwrratio : 6; + uint64_t ivid_vcs : 7; + uint64_t ivid_vdd : 7; +#endif // _BIG_ENDIAN + } fields; + +} lpst_entry_t; + + +/// Standard options controlling Pstate setup and GPSM procedures + +typedef struct { + + /// Option flags; See \ref pstate_options + uint32_t options; + + /// Pad structure to 8 bytes. Could also be used for other options later. + uint32_t pad; + +} PstateOptions; + + +/// An abstract Global Pstate table +/// +/// The GlobalPstateTable is an abstraction of a set of voltage/frequency +/// operating points along with hardware limits. Besides the hardware global +/// Pstate table, the abstract table contains enough extra information to make +/// it the self-contained source for setting up and managing voltage and +/// frequency in either Hardware or Firmware Pstate mode. +/// +/// When installed in PMC, Global Pstate table indices are adjusted such that +/// the defined Pstates begin with table entry 0. The table need not be full - +/// the \a pmin and \a entries fields define the minimum and maximum Pstates +/// represented in the table. However at least 1 entry must be defined to +/// create a legal table. +/// +/// Note that Global Pstate table structures to be mapped into PMC hardware +/// must be 1KB-aligned. This requirement is fullfilled by ensuring that +/// instances of this structure are 1KB-aligned. + +typedef struct { + + /// The Pstate table + gpst_entry_t pstate[GLOBAL_PSTATE_TABLE_ENTRIES]; + + /// Pstate options + /// + /// The options are included as part of the GlobalPstateTable so that they + /// are available to all procedures after gpsm_initialize(). + PstateOptions options; + + /// The frequency associated with Pstate[0] in KHz + uint32_t pstate0_frequency_khz; + + /// The frequency step in KHz + uint32_t frequency_step_khz; + + /// The DPLL frequency code corresponding to Pstate 0 + /// + /// This frequency code is installed in the PCB Slave as the DPLL Fnom + /// when the Pstate table is activated. Normally this frequency code is + /// computed as + /// + /// pstate0_frequency_khz / frequency_step_khz + /// + /// however it may be replaced by any other code as a way to + /// transparently bias frequency on a per-core basis. + DpllCode pstate0_frequency_code[PGP_NCORES]; + + /// The DPLL Fmax bias + /// + /// This bias value (default 0, range -8 to +7 frequency ticks) is + /// installed when the Pstate table is installed. The value is allowed to + /// vary per core. This bias value will usually be set to a small + /// positive number to provide a small amount of frequency headroom for + /// the CPM-DPLL voltage control algorithm. + /// + /// \bug Hardware currently specifies this field as unsigned for the + /// computation of frequency stability in + /// dpll_freqout_mode_en. (HW217404). This issue will be fixed in + /// Venice. Since we never plan to use this mode no workaround or + /// mitigation is provided by GPSM procedures. + + int8_t dpll_fmax_bias[PGP_NCORES]; + + /// The number of entries defined in the table. + uint8_t entries; + + /// The minimum Pstate in the table + /// + /// Note that gpsi_min = pmin - PSTATE_MIN, gpsi_max = pmin + entries - 1. + Pstate pmin; + + /// The "Safe" Global Pstate + /// + /// This Pstate is installed in the PMC and represents the safe-mode + /// voltage. + Pstate pvsafe; + + /// The "Safe" Local Pstate + /// + /// This Pstate is installed in the PCB Slaves and represents the + /// safe-mode frequency. + Pstate psafe; + + /// Step size of Global Pstate steps + uint8_t pstate_stepsize; + + /// The exponent of the exponential encoding of Pstate stepping delay + uint8_t vrm_stepdelay_range; + + /// The significand of the exponential encoding of Pstate stepping delay + uint8_t vrm_stepdelay_value; + + /// Pad structure to 8-byte alignment + uint8_t pad; + +} GlobalPstateTable; + + +/// This macro creates a properly-aligned Global Pstate table structure as a +/// static initialization. + +#define GLOBAL_PSTATE_TABLE(x) \ + GlobalPstateTable x \ + ALIGNED_ATTRIBUTE(POW2_32(GLOBAL_PSTATE_TABLE_ALIGNMENT)) \ + SECTION_ATTRIBUTE(".noncacheable") \ + = {.entries = 0} + + +/// An opaque Local Pstate Array +/// +/// An array local to each core contains the Local Pstate Table, Vds table and +/// Vin table. The array contents are presented to OCC firmware as an opaque +/// set of 96 x 64-bit entries which are simply installed verbatim into each +/// core. Every core stores the same table. +/// +/// When installed in the core, Local Pstate table indices are adjusted such +/// that the defined Pstates begin with table entry 0. The table need not be +/// full - the \a pmin and \a entries fields define the minimum and maximum +/// Pstates represented in the table. However at least 1 entry must be +/// defined to create a legal table. + +typedef struct { + + /// The array contents + lpst_entry_t pstate[LOCAL_PSTATE_ARRAY_ENTRIES]; + + /// The number of entries defined in the Local Pstate Table + uint8_t entries; + + /// The minimum Pstate in the Local Pstate table + /// + /// Note that lpsi_min = pmin - PSTATE_MIN, lpsi_max = pmin + entries - 1. + Pstate pmin; + + /// Pstate step delay for rising iVRM voltages + uint8_t stepdelay_rising; + + /// Pstate step delay for falling iVRM voltages + uint8_t stepdelay_lowering; + + /// Pad structure to 8-byte alignment + uint8_t pad[4]; + +} LocalPstateArray; + + +/// Resonant Clocking setup parameters +/// +/// All Pstate parameters are specified in terms of Pstates as defined in the +/// current PstateSuperStructure. + +typedef struct { + + /// Full Clock Sector Buffer Pstate + Pstate full_csb_ps; + + /// Low-Frequency Resonant Lower Pstate + Pstate res_low_lower_ps; + + /// Low-Frequency Resonant Upper Pstate + Pstate res_low_upper_ps; + + /// High-Frequency Resonant Lower Pstate + Pstate res_high_lower_ps; + + /// High-Frequency Resonant Upper Pstate + Pstate res_high_upper_ps; + + /// Pad structure to 8-byte alignment + uint8_t pad[3]; + +} ResonantClockingSetup; + + + +/// The layout of the data created by the Pstate table creation firmware +/// +/// This structure is only used for passing Pstate data from the FSP into OCC, +/// therefore there is no alignment requirement. The \gpst member is copied +/// to an aligned location, and the \a lpsa and \a resclk members are directly +/// installed in hardware. +/// +/// Both the master and slave OCCs (in DCM-mode) install their Pstate tables +/// independently via the API gpsm_initialize(). At that point the +/// PstateSuperStructure can be discarded. + +typedef struct { + + /// Magic Number + uint64_t magic; + + /// Global Pstate Table + GlobalPstateTable gpst; + + /// Local Pstate Array + LocalPstateArray lpsa; + + /// Resonant Clocking Setup + ResonantClockingSetup resclk; + +} PstateSuperStructure; + + +int +vid11_validate(Vid11 vid); + +int +bias_pstate(Pstate pstate, int bias, Pstate* biased_pstate); + +int +bias_frequency(DpllCode fcode, int bias, DpllCode* biased_fcode); + +int +bias_vid11(Vid11 vid, int bias, Vid11* biased_fcode); + +int +gpst_entry(const GlobalPstateTable* gpst, + const Pstate pstate, + const int bias, + gpst_entry_t* entry); + + +int +freq2pState (const GlobalPstateTable* gpst, + const uint32_t freq_khz, + Pstate* pstate); + +int +gpst_vdd2pstate(const GlobalPstateTable* gpst, + const uint8_t vdd, + Pstate* pstate, + gpst_entry_t* entry); + + +/// Return the Pmin value associated with a GlobalPstateTable +static inline Pstate +gpst_pmin(const GlobalPstateTable* gpst) +{ + return gpst->pmin; +} + + +/// Return the Pmax value associated with a GlobalPstateTable +static inline Pstate +gpst_pmax(const GlobalPstateTable* gpst) +{ + return (int)(gpst->pmin) + (int)(gpst->entries) - 1; +} + +/// Return the Pmin value associated with a LocalPstateTable +static inline Pstate +lpst_pmin(const LocalPstateArray* lpsa) +{ + return lpsa->pmin; +} + + +/// Return the Pmax value associated with a GlobalPstateTable +static inline Pstate +lpst_pmax(const LocalPstateArray* lpsa) +{ + return (int)(lpsa->pmin) + (int)(lpsa->entries) - 1; +} + +#endif /* __ASSEMBLER__ */ + +#endif /* __PSTATES_H__ */ diff --git a/src/usr/hwpf/hwp/pstates/pstates/ssx.h b/src/usr/hwpf/hwp/pstates/pstates/ssx.h new file mode 100755 index 000000000..a0be01120 --- /dev/null +++ b/src/usr/hwpf/hwp/pstates/pstates/ssx.h @@ -0,0 +1,103 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/hwpf/hwp/pstates/pstates/ssx.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 */ +#ifndef __SSX_H__ +#define __SSX_H__ + +// $ID$ + +/// \file ssx.h +/// \brief Dummy "ssx.h" for X86 testing + +#define __SSX__ + +#ifndef __ASSEMBLER__ +#include <stdint.h> +#include <stddef.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +#endif /* __ASSEMBLER__ */ + +#ifndef __ASSEMBLER__ + +#define MIN(X, Y) \ + ({ \ + typeof (X) __x = (X); \ + typeof (Y) __y = (Y); \ + (__x < __y) ? __x : __y; }) + +#define MAX(X, Y) \ + ({ \ + typeof (X) __x = (X); \ + typeof (Y) __y = (Y); \ + (__x > __y) ? __x : __y; \ + }) + +#endif /* __ASSEMBLER__ */ + + +#define SSX_ERROR_CHECK_API 1 +#define SSX_ERROR_CHECK_KERNEL 1 +#define SSX_ERROR_PANIC 1 + +#define SSX_NONCRITICAL 0 +#define SSX_CRITICAL 1 + +#define SSX_INVALID_ARGUMENT 0x00888005 +#define SSX_INVALID_OBJECT 0x0088800e + +typedef int SsxMachineContext; + +static inline void +ssx_critical_section_enter(int priority, SsxMachineContext *ctx) +{} + +static inline void +ssx_critical_section_exit(SsxMachineContext *ctx) +{} + + +#define SSX_PANIC(code) \ + do { \ + fprintf(stderr, "%s : %d : PANIC : 0x%08x\n", \ + __FUNCTION__, __LINE__, code); \ + exit(1); \ + } while (0) + + +/// This macro encapsulates error handling boilerplate in the SSX API +/// functions, for errors that do not occur in critical sections. + +#define SSX_ERROR_IF(condition, code) \ + if (condition) { \ + if (SSX_ERROR_PANIC) { \ + SSX_PANIC(code); \ + } else { \ + return -(code); \ + } \ + } + +#define printk(...) printf(__VA_ARGS__) + +#endif /* __SSX_H__ */ diff --git a/src/usr/hwpf/makefile b/src/usr/hwpf/makefile index 20a31d4c2..390263b75 100644 --- a/src/usr/hwpf/makefile +++ b/src/usr/hwpf/makefile @@ -83,7 +83,9 @@ HWP_ERROR_XML_FILES = hwp/fapiHwpErrorInfo.xml \ hwp/dmi_training/cen_dmi_scominit_errors.xml \ hwp/sbe_centaur_init/cen_xip_customize_errors.xml \ hwp/tod_init/proc_tod_utils/proc_tod_utils.xml \ - hwp/mc_config/mss_eff_config/opt_memmap_errors.xml + hwp/mc_config/mss_eff_config/opt_memmap_errors.xml \ + hwp/pstates/pstates/p8_build_pstate_datablock_errors.xml \ + hwp/pstates/pstates/proc_get_voltage_errors.xml ## these get generated into obj/genfiles/AttributeIds.H HWP_ATTR_XML_FILES = hwp/memory_attributes.xml \ |