summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xsrc/occ_405/amec/amec_parm.h41
-rwxr-xr-xsrc/occ_405/amec/amec_parm_table.c42
-rwxr-xr-xsrc/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.c12
-rwxr-xr-xsrc/occ_405/main.c37
-rw-r--r--src/occ_405/occ_service_codes.h1
-rw-r--r--src/occ_405/pgpe/pgpe_interface.c5
-rw-r--r--src/occ_405/pgpe/pgpe_shared.h8
-rw-r--r--src/occ_405/wof/wof.c635
-rw-r--r--src/occ_405/wof/wof.h111
-rw-r--r--src/occ_405/wof/wof_service_codes.h1
10 files changed, 808 insertions, 85 deletions
diff --git a/src/occ_405/amec/amec_parm.h b/src/occ_405/amec/amec_parm.h
index 83104f9..43a4462 100755
--- a/src/occ_405/amec/amec_parm.h
+++ b/src/occ_405/amec/amec_parm.h
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2015 */
+/* Contributors Listed Below - COPYRIGHT 2011,2017 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -69,10 +69,47 @@ typedef enum
PARM_SOFT_FMIN,
PARM_SOFT_FMAX,
PARM_TOD,
+ // WOF Parameters
+ PARM_V_CORE,
+ PARM_CORE_PWR_ON,
+ PARM_CORES_ON_PER_QUAD,
+ PARM_WOF_DISABLED,
+ PARM_VOLT_VDD_SENSE,
+ PARM_TEMPPROCTHERMC,
+ PARM_TEMPNEST,
+ PARM_TEMPQ,
+ PARM_QUAD_X_PSTATES,
+ PARM_IVRM_STATES,
+ PARM_IDC_VDD,
+ PARM_IDC_QUAD,
+ PARM_VOLTAGE_IDX,
+ PARM_ALL_CORES_OFF_ISO,
+ PARM_ALL_CACHES_ON_ISO,
+ PARM_QUAD_GOOD_CORES_ONLY,
+ PARM_QUAD_ON_CORES,
+ PARM_QUAD_BAD_OFF_CORES,
+ PARM_NEST_MULT,
+ PARM_CORE_MULT,
+ PARM_QUAD_MULT,
+ PARM_NEST_DELTA_TEMP,
+ PARM_CORE_DELTA_TEMP,
+ PARM_QUAD_DELTA_TEMP,
+ PARM_TVPD_LEAK_OFF,
+ PARM_TVPD_LEAK_ON,
+ PARM_TVPD_LEAK_CACHE,
+ PARM_REQ_ACTIVE_QUAD_UPDATE,
+ PARM_PREV_REQ_ACTIVE_QUADS,
+ PARM_CURR_PING_PONG_BUF,
+ PARM_NEXT_PING_PONG_BUF,
+ PARM_CURR_VFRT_MAIN_MEM_ADDR,
+ PARM_ACTIVE_QUADS_SRAM_ADDR,
+ PARM_VFRT_TBLS_MAIN_MEM_ADDR,
+ PARM_VFRT_TBLS_LEN,
+ // End WOF Parameters
AMEC_PARM_NUMBER_OF_PARAMETERS
} AMEC_PARM_ENUM;
-typedef enum
+typedef enum
{
AMEC_PARM_TYPE_UINT8 = 0,
AMEC_PARM_TYPE_UINT16,
diff --git a/src/occ_405/amec/amec_parm_table.c b/src/occ_405/amec/amec_parm_table.c
index cbd994d..bcc7059 100755
--- a/src/occ_405/amec/amec_parm_table.c
+++ b/src/occ_405/amec/amec_parm_table.c
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2015 */
+/* Contributors Listed Below - COPYRIGHT 2011,2017 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -138,6 +138,46 @@ amec_parm_t g_amec_parm_list[] = {
AMEC_PARM_UINT16(PARM_SOFT_FMIN,"part_soft_fmin",&g_amec_sys.part_config.part_list[0].soft_fmin),
AMEC_PARM_UINT16(PARM_SOFT_FMAX,"part_soft_fmax",&g_amec_sys.part_config.part_list[0].soft_fmax),
AMEC_PARM_RAW(PARM_TOD,"apss_tod",&G_dcom_slv_inbox_doorbell_rx.tod,8),
+
+
+
+ // Begin WOF parameters
+ AMEC_PARM_UINT32_ARRAY(PARM_V_CORE, "v_core_100uV", &g_amec_sys.wof.v_core_100uV, MAX_NUM_QUADS),
+ AMEC_PARM_UINT32(PARM_CORE_PWR_ON, "core_pwr_on", &g_amec_sys.wof.core_pwr_on),
+ AMEC_PARM_UINT8_ARRAY(PARM_CORES_ON_PER_QUAD, "coreson_per_quad", &g_amec_sys.wof.cores_on_per_quad, MAX_NUM_QUADS),
+ AMEC_PARM_UINT16(PARM_WOF_DISABLED, "wof_disabled", &g_amec_sys.wof.wof_disabled),
+ AMEC_PARM_UINT32(PARM_VOLT_VDD_SENSE, "volt_vdd_sense", &g_amec_sys.wof.volt_vdd_sense),
+ AMEC_PARM_UINT16_ARRAY(PARM_TEMPPROCTHERMC, "tempprocthrmc", &g_amec_sys.wof.tempprocthrmc, MAX_NUM_CORES),
+ AMEC_PARM_UINT16(PARM_TEMPNEST, "tempnest_sense", &g_amec_sys.wof.tempnest_sense),
+ AMEC_PARM_UINT16_ARRAY(PARM_TEMPQ, "tempq", &g_amec_sys.wof.tempq, MAX_NUM_QUADS),
+ AMEC_PARM_UINT8_ARRAY(PARM_QUAD_X_PSTATES, "quad_x_pstates", &g_amec_sys.wof.quad_x_pstates, MAX_NUM_QUADS),
+ AMEC_PARM_UINT8(PARM_IVRM_STATES, "quad_ivrm_states", &g_amec_sys.wof.quad_ivrm_states),
+ AMEC_PARM_UINT32(PARM_IDC_VDD, "idc_vdd", &g_amec_sys.wof.idc_vdd),
+ AMEC_PARM_UINT32(PARM_IDC_QUAD, "idc_quad", &g_amec_sys.wof.idc_quad),
+ AMEC_PARM_UINT8(PARM_VOLTAGE_IDX, "voltage_idx", &g_amec_sys.wof.voltage_idx),
+ AMEC_PARM_UINT32(PARM_ALL_CORES_OFF_ISO, "allcores_off_iso", &g_amec_sys.wof.all_cores_off_iso),
+ AMEC_PARM_UINT32(PARM_ALL_CACHES_ON_ISO, "allcaches_on_iso", &g_amec_sys.wof.all_caches_on_iso),
+ AMEC_PARM_UINT16_ARRAY(PARM_QUAD_GOOD_CORES_ONLY, "quad_good_cores", &g_amec_sys.wof.quad_good_cores_only, MAX_NUM_QUADS),
+ AMEC_PARM_UINT16_ARRAY(PARM_QUAD_ON_CORES, "quad_on_cores", &g_amec_sys.wof.quad_on_cores, MAX_NUM_QUADS),
+ AMEC_PARM_UINT16_ARRAY(PARM_QUAD_BAD_OFF_CORES,"quadBadOffCores", &g_amec_sys.wof.quad_on_cores, MAX_NUM_QUADS),
+ AMEC_PARM_UINT32(PARM_NEST_MULT, "nest_mult", &g_amec_sys.wof.nest_mult),
+ AMEC_PARM_UINT32_ARRAY(PARM_CORE_MULT, "core_mult", &g_amec_sys.wof.core_mult, MAX_NUM_CORES),
+ AMEC_PARM_UINT32_ARRAY(PARM_QUAD_MULT, "quad_mult", &g_amec_sys.wof.quad_mult, MAX_NUM_QUADS),
+ AMEC_PARM_INT16(PARM_NEST_DELTA_TEMP, "nest_delta_temp", &g_amec_sys.wof.nest_delta_temp),
+ AMEC_PARM_INT16_ARRAY(PARM_CORE_DELTA_TEMP, "core_delta_temp", &g_amec_sys.wof.core_delta_temp, MAX_NUM_CORES),
+ AMEC_PARM_INT16_ARRAY(PARM_QUAD_DELTA_TEMP, "quad_delta_temp", &g_amec_sys.wof.quad_delta_temp, MAX_NUM_CORES),
+ AMEC_PARM_UINT16(PARM_TVPD_LEAK_OFF, "tvpd_leak_off", &g_amec_sys.wof.tvpd_leak_off),
+ AMEC_PARM_UINT16(PARM_TVPD_LEAK_ON, "tvpd_leak_on", &g_amec_sys.wof.tvpd_leak_on),
+ AMEC_PARM_UINT16(PARM_TVPD_LEAK_CACHE, "tvpd_leak_cache", &g_amec_sys.wof.tvpd_leak_cache),
+ AMEC_PARM_UINT8(PARM_REQ_ACTIVE_QUAD_UPDATE, "req_active_quad", &g_amec_sys.wof.req_active_quad_update),
+ AMEC_PARM_UINT8(PARM_PREV_REQ_ACTIVE_QUADS, "prevActiveQuads", &g_amec_sys.wof.prev_req_active_quads),
+ AMEC_PARM_UINT32(PARM_CURR_PING_PONG_BUF, "currPingPongBuf", &g_amec_sys.wof.curr_ping_pong_buf),
+ AMEC_PARM_UINT32(PARM_NEXT_PING_PONG_BUF, "nextPingPongBuf", &g_amec_sys.wof.next_ping_pong_buf),
+ AMEC_PARM_UINT32(PARM_CURR_VFRT_MAIN_MEM_ADDR, "vfrtMainMemAddr", &g_amec_sys.wof.curr_vfrt_main_mem_addr),
+ AMEC_PARM_UINT32(PARM_ACTIVE_QUADS_SRAM_ADDR, "activQuadSramPtr", &g_amec_sys.wof.active_quads_sram_addr),
+ AMEC_PARM_UINT32(PARM_VFRT_TBLS_MAIN_MEM_ADDR, "vfrtMainMemAddr", &g_amec_sys.wof.vfrt_tbls_main_mem_addr),
+ AMEC_PARM_UINT32(PARM_VFRT_TBLS_LEN, "vfrt_tbls_len", &g_amec_sys.wof.vfrt_tbls_len),
+ // End WOF parameters
};
//Throw a compiler error when the enum and array are not both updated
diff --git a/src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.c b/src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.c
index 2c7e90b..8afaf67 100755
--- a/src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.c
+++ b/src/occ_405/cmdh/cmdh_fsp_cmds_datacnfg.c
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2016 */
+/* Contributors Listed Below - COPYRIGHT 2011,2017 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -44,6 +44,7 @@
#include "memory.h"
#include <avsbus.h>
#include "p9_pstates_occ.h"
+#include <wof.h>
#define FREQ_FORMAT_PWR_MODE_NUM 6
#define FREQ_FORMAT_BASE_DATA_SZ (sizeof(cmdh_store_mode_freqs_t) - sizeof(cmdh_fsp_cmd_header_t))
@@ -1094,14 +1095,21 @@ errlHndl_t data_store_avsbus_config(const cmdh_fsp_cmd_t * i_cmd_ptr,
l_invalid_data = TRUE;
}
- if (l_invalid_data)
+ if (l_invalid_data || !G_avsbus_vdd_monitoring || !G_avsbus_vdn_monitoring)
{
cmdh_build_errl_rsp(i_cmd_ptr, o_rsp_ptr, ERRL_RC_INVALID_DATA, &l_err);
G_avsbus_vdd_monitoring = FALSE;
G_avsbus_vdn_monitoring = FALSE;
+
+ // If cannot use vdd/vdn, cannot run wof algorithm.
+ g_amec->wof.wof_disabled |= WOF_RC_NO_VDD_VDN_READ_MASK;
+
}
else
{
+ // We can use vdd/vdn. Clear NO_VDD_VDN_READ mask
+ g_amec->wof.wof_disabled &= ~WOF_RC_NO_VDD_VDN_READ_MASK;
+
avsbus_init();
}
diff --git a/src/occ_405/main.c b/src/occ_405/main.c
index 688be99..0779319 100755
--- a/src/occ_405/main.c
+++ b/src/occ_405/main.c
@@ -79,10 +79,6 @@ extern uint32_t G_pgpe_beacon_address;
extern uint32_t G_proc_fmin_khz;
extern uint32_t G_proc_fmax_khz;
-extern uint32_t G_wof_active_quads_sram_addr;
-extern uint32_t G_wof_tables_main_mem_addr;
-extern uint32_t G_wof_tables_len;
-extern bool G_run_wof_main;
extern wof_header_data_t G_wof_header;
extern uint32_t G_khz_per_pstate;
@@ -93,8 +89,10 @@ extern uint8_t G_proc_pmax;
IMAGE_HEADER (G_mainAppImageHdr,__ssx_boot,MAIN_APP_ID,ID_NUM_INVALID);
// PGPE Image Header Parameters
-uint32_t G_pgpe_shared_sram_address = 0;
-uint32_t G_pgpe_shared_sram_sz = 0;
+uint32_t G_pgpe_shared_sram_address;
+uint32_t G_pgpe_shared_sram_sz;
+uint32_t G_pgpe_pstate_table_address;
+uint32_t G_pgpe_pstate_table_sz;
ppmr_header_t G_ppmr_header; // PPMR Header layout format
OCCPstateParmBlock G_oppb; // OCC Pstate Parameters Block Structure
@@ -513,9 +511,9 @@ void read_wof_header(void)
// 128 byte aligned buffer to read the data
temp_bce_request_buffer_t l_temp_bce_buff = {{0}};
- uint32_t pad = G_wof_tables_main_mem_addr%128;
+ uint32_t pad = g_amec->wof.vfrt_tbls_main_mem_addr%128;
// Force WOF tables address is on 128 byte boundary
- uint32_t wof_main_mem_addr_128 = G_wof_tables_main_mem_addr - pad;
+ uint32_t wof_main_mem_addr_128 = g_amec->wof.vfrt_tbls_main_mem_addr - pad;
// Create request
l_ssxrc = bce_request_create(&l_wof_header_req, // block copy object
&G_pba_bcde_queue, // main to sram copy engine
@@ -581,6 +579,7 @@ void read_wof_header(void)
* @moduleid READ_WOF_HEADER
* @reasoncode INVALID_ACTIVE_QUAD_COUNT
* @userdata1 Reported active quad count
+ * @userdata4 Quad count failure
* @devdesc Read an invalid number of active quads
*/
l_reasonCode = INVALID_ACTIVE_QUAD_COUNT;
@@ -604,7 +603,7 @@ void read_wof_header(void)
commitErrl(&l_errl);
// We were unable to get the active quad count. Do not run wof algo.
- G_run_wof_main = false;
+ g_amec->wof.wof_disabled |= WOF_RC_INVALID_ACTIVE_QUADS_MASK;
}
@@ -632,8 +631,7 @@ void read_wof_header(void)
commitErrl(&l_errl);
// We were unable to get the WOF header thus it should not be run.
- G_run_wof_main = false;
-
+ g_amec->wof.wof_disabled |= WOF_RC_NO_WOF_HEADER_MASK;
return;
}
@@ -700,15 +698,15 @@ void read_pgpe_header(void)
G_pgpe_beacon_address);
// Read active quads address, wof tables address, and wof tables len
- G_wof_active_quads_sram_addr = in32(PGPE_ACTIVE_QUAD_ADDR_PTR);
- G_wof_tables_main_mem_addr = in32(PGPE_WOF_TBLS_ADDR_PTR);
- G_wof_tables_len = in32(PGPE_WOF_TBLS_LEN_PTR);
+ g_amec->wof.active_quads_sram_addr = in32(PGPE_ACTIVE_QUAD_ADDR_PTR);
+ g_amec->wof.vfrt_tbls_main_mem_addr = in32(PGPE_WOF_TBLS_ADDR_PTR);
+ g_amec->wof.vfrt_tbls_len = in32(PGPE_WOF_TBLS_LEN_PTR);
MAIN_TRAC_IMP("Read WOF Tables Main Memory Address[0x%08x], Len[0x%08x],"
" Active Quads Address[0x%08x]",
- G_wof_tables_main_mem_addr,
- G_wof_tables_len,
- G_wof_active_quads_sram_addr );
+ g_amec->wof.vfrt_tbls_main_mem_addr,
+ g_amec->wof.vfrt_tbls_len,
+ g_amec->wof.active_quads_sram_addr );
// Extract important WOF data into global space
read_wof_header();
@@ -720,6 +718,11 @@ void read_pgpe_header(void)
MAIN_TRAC_IMP("Read PGPE Shared SRAM Start Address[0x%08x], Size[0x%08x]",
G_pgpe_shared_sram_address, G_pgpe_shared_sram_sz);
+ // Read OCC Pstate table address and size
+ G_pgpe_pstate_table_address = in32(PGPE_PSTATE_TBL_ADDR_PTR);
+ G_pgpe_pstate_table_sz = in32(PGPE_PSTATE_TBL_SZ_PTR);
+
+
// PGPE Beacon is not implemented in simics yet
// the G_pgpe_shared_sram_address and G_pgpe_shared_sram_sz pointers don't
// have the proper values yet.
diff --git a/src/occ_405/occ_service_codes.h b/src/occ_405/occ_service_codes.h
index c55194f..beb46b5 100644
--- a/src/occ_405/occ_service_codes.h
+++ b/src/occ_405/occ_service_codes.h
@@ -122,6 +122,7 @@ enum occReasonCode
GPE_REQUEST_TASK_TIMEOUT = 0xD6,
GPE_REQUEST_RC_FAILURE = 0xD7,
+ WOF_VFRT_REQ_FAILURE = 0xD8,
INVALID_MAGIC_NUMBER = 0xDA,
/// Success!
diff --git a/src/occ_405/pgpe/pgpe_interface.c b/src/occ_405/pgpe/pgpe_interface.c
index b459b44..f6a5b4a 100644
--- a/src/occ_405/pgpe/pgpe_interface.c
+++ b/src/occ_405/pgpe/pgpe_interface.c
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER OnChipController Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2016 */
+/* Contributors Listed Below - COPYRIGHT 2011,2017 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -36,6 +36,7 @@
#include "proc_data_control.h"
#include "occ_sys_config.h"
#include "ssx.h"
+#include "wof.h"
extern opal_static_table_t G_opal_static_table;
@@ -374,7 +375,7 @@ errlHndl_t pgpe_init_wof_vfrt(void)
IPC_MSGID_405_WOF_VFRT, // Function ID
&G_wof_vfrt_parms, // Task parameters
SSX_WAIT_FOREVER, // Timeout (none)
- NULL, // Callback
+ (AsyncRequestCallback)switch_ping_pong_buffer, // Callback
NULL, // Callback arguments
ASYNC_CALLBACK_IMMEDIATE); // Options
diff --git a/src/occ_405/pgpe/pgpe_shared.h b/src/occ_405/pgpe/pgpe_shared.h
index e185e7b..e74d843 100644
--- a/src/occ_405/pgpe/pgpe_shared.h
+++ b/src/occ_405/pgpe/pgpe_shared.h
@@ -31,6 +31,8 @@
// Offset addresses of PGPE Header parameters (relative to start address)
#define PGPE_SHARED_SRAM_ADDR_OFFSET 0x0c
#define PGPE_SHARED_SRAM_SZ_OFFSET 0x14
+#define PGPE_PSTATE_TBL_ADDR_OFFSET 0x40
+#define PGPE_PSTATE_TBL_SZ_OFFSET 0x44
#define PGPE_BEACON_ADDR_OFFSET 0x48
#define PGPE_ACTIVE_QUAD_ADDR_OFFSET 0x4c
#define PGPE_WOF_TBLS_ADDR_OFFSET 0x50
@@ -53,7 +55,11 @@
#define PGPE_WOF_TBLS_ADDR_PTR (PGPE_HEADER_ADDR + PGPE_WOF_TBLS_ADDR_OFFSET)
#define PGPE_WOF_TBLS_LEN_PTR (PGPE_HEADER_ADDR + PGPE_WOF_TBLS_LEN_OFFSET)
-// PMMR (Pstates PM region) in HOMMR
+// Pointers to Pstate tables in SRAM
+#define PGPE_PSTATE_TBL_ADDR_PTR (PGPE_HEADER_ADDR + PGPE_PSTATE_TBL_ADDR_OFFSET)
+#define PGPE_PSTATE_TBL_SZ_PTR (PGPE_HEADER_ADDR + PGPE_PSTATE_TBL_SZ_OFFSET)
+
+// PPMR (Pstates PM region) in HOMMR
#define PPMR_OPPM_ADDR_OFFSET 0x40 //offset of the OCC Pstates Parameter Block address in the PPMR header
#define PPMR_OPPM_SZ_OFFSET 0x44 //offset of the OCC Pstates Parameter Block size in the PPMR header
diff --git a/src/occ_405/wof/wof.c b/src/occ_405/wof/wof.c
index b0f7457..08a204b 100644
--- a/src/occ_405/wof/wof.c
+++ b/src/occ_405/wof/wof.c
@@ -31,34 +31,71 @@
#include <p9_pstates_occ.h>
#include <occ_service_codes.h>
#include <wof_service_codes.h>
+#include <amec_sys.h>
+#include <occ_sys_config.h>
#include "wof.h"
+//******************************************************************************
+// External Globals
+//******************************************************************************
+extern amec_sys_t g_amec_sys;
+extern OCCPstateParmBlock G_oppb;
+extern GPE_BUFFER(ipcmsg_wof_vfrt_t G_wof_vfrt_parms);
+extern GpeRequest G_wof_vfrt_req;
+extern uint32_t G_pgpe_shared_sram_address;
+extern uint32_t G_pgpe_pstate_table_address;
+extern uint32_t G_pgpe_pstate_table_sz;
//******************************************************************************
// Globals
//******************************************************************************
-uint32_t G_wof_active_quads_sram_addr;
-uint32_t G_wof_tables_main_mem_addr;
-uint32_t G_wof_tables_len;
-uint8_t G_requested_active_quad_update;
-uint8_t G_previous_active_quads;
-bool G_run_wof_main;
uint8_t G_sram_vfrt_ping_buffer[MIN_BCE_REQ_SIZE] __attribute__ ((section(".vfrt_ping_buffer")));
uint8_t G_sram_vfrt_pong_buffer[MIN_BCE_REQ_SIZE] __attribute__ ((section(".vfrt_pong_buffer")));
-uint8_t * G_current_ping_pong_buf;
+
wof_header_data_t G_wof_header __attribute__ ((section (".global_data")));
-uint32_t G_current_vfrt_addr = 0;
+
+// Quad state structs to temporarily hold the data from the doublewords to
+// then populate in amec structure
quad_state0_t G_quad_state_0 = {0};
-quad_state0_t G_quad_state_1 = {0};
+quad_state1_t G_quad_state_1 = {0};
-//******************************************************************************
-// External Globals
-//******************************************************************************
-extern OCCPstateParmBlock G_oppb;
-extern GPE_BUFFER(ipcmsg_wof_vfrt_t G_wof_vfrt_parms);
-extern GpeRequest G_wof_vfrt_req;
-extern uint32_t G_pgpe_shared_sram_address;
+// Create a pointer to amec WOF structure
+amec_wof_t * g_wof = &(g_amec_sys.wof);
+
+// Core IDDQ voltages array (voltages in 100uV)
+uint16_t G_iddq_voltages[CORE_IDDQ_MEASUREMENTS] =
+{
+ 6000,
+ 7000,
+ 8000,
+ 9000,
+ 10000,
+ 11000
+};
+
+// Approximate y = 1.3^((T-tvpd_leak)/10)
+// Interpolate (T-tvpd_leak) in the table below to find m.
+// y ~= (T*m) >> 10 (shift out 10 bits)
+// Error in estimation is no more than 0.9%
+// The first column represents the result of T-tvpd_leak where T is the
+// associated temperature sensor. The second column represents the associated
+// m(slope) when the delta temp the first value.
+int16_t G_wof_iddq_mult_table[][2] = {
+ //Delta Temperature in C, m
+ {-50, 276},
+ {-40, 359},
+ {-30, 466},
+ {-20, 606},
+ {-10, 788},
+ {0, 1024},
+ {10, 1331},
+ {20, 1731},
+ {30, 2250},
+ {40, 2925},
+ {50, 3802}
+};
+#define WOF_IDDQ_MULT_TABLE_N 11
/**
@@ -76,6 +113,10 @@ void wof_main(void)
// TODO Read out necessary Sensor data for WOF calculation
// uint16_t l_current_vdd = getSensorByGsid(CURVDD)->sample;
// uint16_t l_current_vdn = getSensorByGsid(CURVDN)->sample
+
+ // Read VOLTVDDSENSE once here to be used in the algorithm and save it to amec
+ g_wof->volt_vdd_sense = getSensorByGsid(VOLTVDDSENSE)->sample;
+
// Functions to calculate Ceff_vdd and Ceff_vdn here.
uint16_t ceff_vdd = 0; // TODO: replace with future function call
uint16_t ceff_vdn = 0; // TODO: replace with future function call
@@ -98,12 +139,11 @@ void wof_main(void)
// NOTE to Reviewers: This trace is here just to put references to the above
// variables such that compilation is successful. Will be removed in final
// version
- TRAC_INFO("Step from start VDN = %d, VDN = %d",
+ TRAC_INFO("Step from start VDN = %d, VDD = %d",
vdn_step_from_start,
vdd_step_from_start );
-
}
@@ -198,7 +238,7 @@ uint32_t calc_vfrt_mainstore_addr( uint16_t i_vdd_step_from_start,
i_vdd_step_from_start) ) + i_quad_step_from_start);
// Skip the wof header at the beginning of wof tables
- uint32_t wof_tables_base = G_wof_tables_main_mem_addr + WOF_HEADER_SIZE;
+ uint32_t wof_tables_base = g_wof->vfrt_tbls_main_mem_addr + WOF_HEADER_SIZE;
return wof_tables_base + offset;
}
@@ -227,20 +267,23 @@ void copy_vfrt_to_sram( copy_vfrt_to_sram_parms_t * i_parms)
// Static variable to trac which buffer is open for use
// 0 = PING; 1 = PONG;
int l_gperc; // gpe schedule return code
- static uint8_t L_pingpong = 0;
uint8_t * l_buffer_address;
- if( L_pingpong == 0 )
+
+ if(g_wof->curr_ping_pong_buf == (uint32_t)G_sram_vfrt_ping_buffer)
{
- // Use ping buffer
- l_buffer_address = G_sram_vfrt_ping_buffer;
+ // Switch to pong buffer
+ l_buffer_address = G_sram_vfrt_pong_buffer;
}
else
{
- // Use pong buffer
- l_buffer_address = G_sram_vfrt_pong_buffer;
+ // Switch to ping buffer
+ l_buffer_address = G_sram_vfrt_ping_buffer;
}
+ // Update global "next" ping pong buffer for callback function
+ g_wof->next_ping_pong_buf = (uint32_t)l_buffer_address;
+
// Copy the vfrt data into the buffer
memcpy( l_buffer_address,
&(i_parms->vfrt_table->data[i_parms->pad]),
@@ -248,7 +291,7 @@ void copy_vfrt_to_sram( copy_vfrt_to_sram_parms_t * i_parms)
// Set the parameters for the GpeRequest
G_wof_vfrt_parms.vfrt_ptr = l_buffer_address;
- G_wof_vfrt_parms.active_quads = G_requested_active_quad_update;
+ G_wof_vfrt_parms.active_quads = g_wof->req_active_quad_update;
// Send IPC command to PGPE with new vfrt address and active quads
// Should not need to check if request is idle as wof_main does before
@@ -291,21 +334,62 @@ void copy_vfrt_to_sram( copy_vfrt_to_sram_parms_t * i_parms)
// Commit error log
commitErrl(&l_errl);
}
- else
- {
- // Sent the IPC command successfully, update which buffer we should look
- // at next time.
- L_pingpong = ~L_pingpong;
- // Update the previous active quads
- G_previous_active_quads = G_requested_active_quad_update;
+}
- // Update Current ping pong buffer
- G_current_ping_pong_buf = l_buffer_address;
+/**
+ * switch_ping_pong_buffer
+ *
+ * Description: Callback function for G_wof_vfrt_req GPE request to
+ * confirm the new VFRT is being used by the PGPE and
+ * record the switch on the 405
+ */
+//TODO RTC 166301 - will be renamed wof_vfrt_req_callback
+void switch_ping_pong_buffer( void )
+{
+ // Confirm the WOF VFRT PGPE request has completed with no errors
+ if( G_wof_vfrt_parms.msg_cb.rc == PGPE_WOF_RC_VFRT_QUAD_MISMATCH )
+ {
+ // TODO RTC 166301 - Implement this logic with read_req_active_quads
+ // function.
+ // Quad Mismatch.
+ // Reread the requested active quads from Shared SRAM and set
+ // parameters
+ // Trace the mismatch and let the code exit. Will retry
+ // next invocation of wof_main.
+ // Keep retrying if this return code is seen
}
+ else if( G_wof_vfrt_parms.msg_cb.rc == PGPE_RC_SUCCESS )
+ {
+ // GpeRequest went through successfully. update global ping pong buffer
+ g_wof->curr_ping_pong_buf = g_wof->next_ping_pong_buf;
-}
+ // Update previous active quads
+ g_wof->prev_req_active_quads = g_wof->req_active_quad_update;
+ }
+ else
+ {
+ // Some other failure case. Reset PM complex.
+ /* @
+ * @errortype
+ * @moduleid WOF_VFRT_CALLBACK
+ * @reasoncode WOF_VFRT_REQ_FAILURE
+ * @userdata1 The GpeRequest RC
+ * @userdata4 OCC_NO_EXTENDED_RC
+ */
+ errlHndl_t l_errl = createErrl( WOF_VFRT_CALLBACK,
+ WOF_VFRT_REQ_FAILURE,
+ OCC_NO_EXTENDED_RC,
+ ERRL_SEV_UNRECOVERABLE,
+ NULL,
+ DEFAULT_TRACE_SIZE,
+ G_wof_vfrt_parms.msg_cb.rc,
+ 0 );
+
+ REQUEST_RESET( l_errl );
+ }
+}
/**
* send_vfrt_to_pgpe
@@ -315,9 +399,9 @@ void copy_vfrt_to_sram( copy_vfrt_to_sram_parms_t * i_parms)
* to the PGPE
* Note: If desired VFRT is the same as previous, skip.
*
- * Param[in]: i_vfrt_address - Address of the desired vfrt table.
+ * Param[in]: i_vfrt_main_mem_addr - Address of the desired vfrt table.
*/
-void send_vfrt_to_pgpe( uint32_t i_vfrt_address )
+void send_vfrt_to_pgpe( uint32_t i_vfrt_main_mem_addr )
{
int l_ssxrc = SSX_OK;
int l_gperc = 0;
@@ -326,19 +410,21 @@ void send_vfrt_to_pgpe( uint32_t i_vfrt_address )
do
{
- if( (i_vfrt_address == G_current_vfrt_addr ) &&
- (G_requested_active_quad_update == G_previous_active_quads) )
+ if( (i_vfrt_main_mem_addr == g_wof->curr_vfrt_main_mem_addr ) &&
+ (g_wof->req_active_quad_update ==
+ g_wof->prev_req_active_quads) )
{
// VFRT and requested active quads are unchanged. Skip
break;
}
- else if( (i_vfrt_address == G_current_vfrt_addr) &&
- (G_requested_active_quad_update != G_previous_active_quads) )
+ else if( (i_vfrt_main_mem_addr == g_wof->curr_vfrt_main_mem_addr)&&
+ (g_wof->req_active_quad_update !=
+ g_wof->prev_req_active_quads) )
{
// Only requested active quads changed. No need to do a BCE request
// for new VFRT. Just send IPC command with updated active quads
- G_wof_vfrt_parms.vfrt_ptr = G_current_ping_pong_buf;
- G_wof_vfrt_parms.active_quads = G_requested_active_quad_update;
+ G_wof_vfrt_parms.vfrt_ptr = (VFRT_Hcode_t*)g_wof->curr_ping_pong_buf;
+ G_wof_vfrt_parms.active_quads = g_wof->req_active_quad_update;
//Send IPC command to PGPE with new active quad update
l_gperc = gpe_request_schedule( &G_wof_vfrt_req );
@@ -347,7 +433,7 @@ void send_vfrt_to_pgpe( uint32_t i_vfrt_address )
if(l_gperc != 0)
{
//Error in scheduling pgpe clip update task
- TRAC_ERR("copy_vfrt_to_sram: Failed to schedule WOF VFRT task rc=%x",
+ TRAC_ERR("send_vfrt_to_sram: Failed to schedule WOF VFRT task rc=%x",
l_gperc);
/* @
@@ -379,11 +465,6 @@ void send_vfrt_to_pgpe( uint32_t i_vfrt_address )
// Commit error log
commitErrl(&l_errl);
}
- else
- {
- // Successful Schedule. Update previous active quads
- G_previous_active_quads = G_requested_active_quad_update;
- }
}
else
{
@@ -394,8 +475,8 @@ void send_vfrt_to_pgpe( uint32_t i_vfrt_address )
temp_bce_request_buffer_t l_temp_bce_buff = {{0}};
- uint8_t l_pad = i_vfrt_address%128;
- uint32_t l_vfrt_addr_128_aligned = i_vfrt_address - l_pad;
+ uint8_t l_pad = i_vfrt_main_mem_addr%128;
+ uint32_t l_vfrt_addr_128_aligned = i_vfrt_main_mem_addr - l_pad;
// Create structure to hold parameters for callback function
copy_vfrt_to_sram_parms_t l_callback_parms;
@@ -417,7 +498,7 @@ void send_vfrt_to_pgpe( uint32_t i_vfrt_address )
if(l_ssxrc != SSX_OK)
{
- CMDH_TRAC_ERR("read_wof_header: BCDE request create failure rc=[%08X]", -l_ssxrc);
+ CMDH_TRAC_ERR("send_vfrt_to_pgpe: BCDE request create failure rc=[%08X]", -l_ssxrc);
/*
* @errortype
* @moduleid SEND_VFRT_TO_PGPE
@@ -437,7 +518,7 @@ void send_vfrt_to_pgpe( uint32_t i_vfrt_address )
if(l_ssxrc != SSX_OK)
{
- CMDH_TRAC_ERR("read_wof_header: BCE request schedule failure rc=[%08X]", -l_ssxrc);
+ CMDH_TRAC_ERR("send_vfrt_to_pgpe: BCE request schedule failure rc=[%08X]", -l_ssxrc);
/*
* @errortype
* @moduleid SEND_VFRT_TO_PGPE
@@ -500,6 +581,450 @@ void read_shared_sram( void )
// Get the requested active quad update
uint64_t l_doubleword = in64(current_pgpe_sram_addr);
- memcpy(&G_requested_active_quad_update, &l_doubleword, sizeof(uint8_t));
+ memcpy(&g_wof->req_active_quad_update, &l_doubleword, sizeof(uint8_t));
+
+ // merge the 16-bit power-on field from quad state 0 and the 16-bit power-on
+ // field from quad state 1 and save it to amec.
+ g_wof->core_pwr_on =
+ (((uint32_t)G_quad_state_0.fields.core_poweron_state) << 16)
+ | ((uint32_t)G_quad_state_1.fields.core_poweron_state);
+
+ // Clear out current quad pstates
+ memset(g_wof->quad_x_pstates, 0 , MAX_NUM_QUADS);
+
+ // Add the quad states to the global quad state array for easy looping.
+ g_wof->quad_x_pstates[0] = (uint8_t)G_quad_state_0.fields.quad0_pstate;
+ g_wof->quad_x_pstates[1] = (uint8_t)G_quad_state_0.fields.quad1_pstate;
+ g_wof->quad_x_pstates[2] = (uint8_t)G_quad_state_0.fields.quad2_pstate;
+ g_wof->quad_x_pstates[3] = (uint8_t)G_quad_state_0.fields.quad3_pstate;
+ g_wof->quad_x_pstates[4] = (uint8_t)G_quad_state_1.fields.quad4_pstate;
+ g_wof->quad_x_pstates[5] = (uint8_t)G_quad_state_1.fields.quad5_pstate;
+
+
+ // Save IVRM bit vector states to amec
+ g_wof->quad_ivrm_states =
+ (((uint8_t)G_quad_state_0.fields.ivrm_state) << 4)
+ | ((uint8_t)G_quad_state_1.fields.ivrm_state);
}
+
+/**
+ * calculate_core_voltage
+ *
+ * Description: Calculate the core voltage based on Pstate and IVRM state.
+ * Same for all cores in the quad so only need to calculate
+ * once per quad.
+ */
+void calculate_core_voltage( void )
+{
+ uint32_t l_voltage;
+ uint8_t l_quad_mask;
+ int l_quad_idx = 0;
+ for(; l_quad_idx < MAX_NUM_QUADS; l_quad_idx++)
+ {
+ // Adjust current mask. (IVRM_STATE_QUAD_MASK = 0x80)
+ l_quad_mask = IVRM_STATE_QUAD_MASK >> l_quad_idx;
+
+ // Check IVRM state of quad 0.
+ // 0 = BYPASS, 1 = REGULATION
+ if( (g_wof->quad_ivrm_states & l_quad_mask ) == 0 )
+ {
+ l_voltage = g_wof->volt_vdd_sense;
+ }
+ else
+ {
+ // Calculate the address of the pstate for the current quad.
+ uint32_t pstate_addr = G_pgpe_pstate_table_address +
+ (g_wof->quad_x_pstates[l_quad_idx] * sizeof(OCCPstateTable_entry_t));
+
+ // Get the Pstate
+ OCCPstateTable_entry_t * pstate_entry_ptr;
+ uint32_t current_pstate = in32(pstate_addr);
+ pstate_entry_ptr = (OCCPstateTable_entry_t *)(&current_pstate);
+
+ // Get the internal vid (ivid) from the pstate table
+ uint8_t current_vid = pstate_entry_ptr->internal_vdd_vid;
+
+ // Convert the vid to voltage and then convert units to 100uV
+ // Vid-to-voltage = 512mV + ivid*4mV
+ // mV to 100uV = mV*10
+ l_voltage = (512 + (current_vid*4))*10;
+ }
+
+ // Save the voltage to amec_wof_t global struct
+ g_wof->v_core_100uV[l_quad_idx] = l_voltage;
+ }
+}
+
+
+/**
+ * calculate_core_leakage
+ *
+ * Description: Calculate core-level leakage
+ *
+ * Return: the calculated core leakage
+ */
+void calculate_core_leakage( void )
+{
+
+ int l_chip_v_idx = 0;
+ uint16_t l_quad_x_cache;
+ uint16_t idc_vdd = 0;
+ uint8_t num_quads_off = 0;
+ uint16_t temperature = 0;
+
+ // Get the VOLTVDDSENSE sensor and choose the appropriate
+ // chip voltage index
+ uint32_t l_v_chip = g_wof->volt_vdd_sense;
+
+ if( l_v_chip <= G_iddq_voltages[0] )
+ {
+ // Voltage is <= to first entry. Use first two entries.
+ l_chip_v_idx = 0;
+ }
+ else if( l_v_chip >= G_iddq_voltages[CORE_IDDQ_MEASUREMENTS-1] )
+ {
+ // Voltage is >= to last entry. Use last two entries.
+ l_chip_v_idx = CORE_IDDQ_MEASUREMENTS - 2;
+ }
+ else
+ {
+ // Search for entries on either side of our voltage
+ for(;l_chip_v_idx < CORE_IDDQ_MEASUREMENTS - 1; l_chip_v_idx++)
+ {
+ if( (l_v_chip >= G_iddq_voltages[l_chip_v_idx]) &&
+ (l_v_chip <= G_iddq_voltages[l_chip_v_idx]) )
+ {
+ break;
+ }
+ }
+
+ }
+ // Save index used for interpolating voltages to amec
+ g_wof->voltage_idx = l_chip_v_idx;
+
+
+ // Calculate all variables that will be used in the core
+ // loop that only need to be calculated once.
+
+ // Read the Nest Temperature sensor for calculations & save to amec
+ g_wof->tempnest_sense = getSensorByGsid(TEMPNEST)->sample;
+
+ // Look up Tvpd_leak for calculations when either the core or quad is off
+ // avttemp values in 0.5C. Divide by 2 to convert to 1C
+ g_wof->tvpd_leak_off =
+ G_oppb.iddq.avgtemp_all_cores_off_caches_off[l_chip_v_idx] >> 1;
+
+ // Look up Tvpd_leak for calculations involving the cache.
+ g_wof->tvpd_leak_cache =
+ G_oppb.iddq.avgtemp_all_good_cores_off[l_chip_v_idx] >> 1;
+
+ // Take the difference between the temperature and tvpd_leak_off
+ // used for multiplier calculation
+ g_wof->nest_delta_temp = g_wof->tempnest_sense -
+ g_wof->tvpd_leak_off;
+
+ // Calculate IDDQ_TEMP_FACTOR^((TEMPNEST - tvpd_leak)/10)
+ g_wof->nest_mult = calculate_multiplier(g_wof->nest_delta_temp);
+
+
+ // Look up leakage current.
+ // Divide by 6 to get just one quad
+ g_wof->idc_quad =
+ G_oppb.iddq.ivdd_all_cores_off_caches_off[l_chip_v_idx] /
+ MAX_NUM_QUADS;
+
+
+
+
+ // Calculate ALL_CORES_OFF_ISO
+ // Perform linear interpolation using the neighboring entries:
+ // Y = m*(X-x1) + y1, where m = (y2-y1) / (x2-x1)
+ g_wof->all_cores_off_iso =
+ interpolate_linear((int32_t)l_v_chip,
+ (int32_t)G_iddq_voltages[l_chip_v_idx],
+ (int32_t)G_iddq_voltages[l_chip_v_idx+1],
+ (int32_t)G_oppb.iddq.ivdd_all_cores_off_caches_off[l_chip_v_idx],
+ (int32_t)G_oppb.iddq.ivdd_all_cores_off_caches_off[l_chip_v_idx+1]);
+
+ // Multiply by nest leakage percentage
+ // TODO: This percentage(60%) will eventually be added to the OCC Pstate Parameter
+ // block once it is added as a system attribute to the MRW.
+ // G_oppb.iddq.nestLeakagePercentage
+ g_wof->all_cores_off_iso = g_wof->all_cores_off_iso * 60 / 100;
+
+
+ // Calculate ALL_CACHES_ON_ISO
+ g_wof->all_caches_on_iso =
+ G_oppb.iddq.ivdd_all_good_cores_off_good_caches_on[l_chip_v_idx] -
+ g_wof->all_cores_off_iso;
+
+ l_quad_x_cache = g_wof->all_caches_on_iso / MAX_NUM_QUADS;
+
+ // Loop through all Quads and their respective Cores to calculate
+ // leakage.
+ int quad_idx = 0; // Quad Index (0-5)
+ uint8_t core_idx = 0; // Actual core index (0-23)
+ int core_loop_idx = 0; // On a per quad basis (0-3)
+
+
+
+ for(quad_idx = 0; quad_idx < MAX_NUM_QUADS; quad_idx++)
+ {
+ if(g_wof->quad_x_pstates[quad_idx] == QUAD_POWERED_OFF)
+ {
+ // Increment the number of quads found to be off
+ num_quads_off++;
+
+ }
+ else // Quad i is on
+ {
+ // Calculate the index of the first core in the quad.
+ core_idx = quad_idx * NUM_CORES_PER_QUAD;
+
+ // Get the voltage for the current core.
+ // (Same for all cores within a single quad)
+ uint16_t cur_core_voltage = g_wof->v_core_100uV[quad_idx];
+
+ // Calculate the number of cores on within the current quad.
+ g_wof->cores_on_per_quad[quad_idx] =
+ num_cores_on_in_quad(quad_idx);
+
+ // Look up tvpd_leak_on for calculations when the core/quad is on
+ // avttemp in IDDQ table is in 0.5C. Divide by 2 to convert to 1C.
+ g_wof->tvpd_leak_on = G_oppb.iddq.avgtemp_quad_good_cores_on
+ [quad_idx][cur_core_voltage] >> 1;
+
+
+ // Calculate Quadx_good_cores_only
+ g_wof->quad_good_cores_only[quad_idx] =
+ G_oppb.iddq.ivdd_quad_good_cores_on_good_caches_on
+ [quad_idx][cur_core_voltage] -
+ G_oppb.iddq.ivdd_all_good_cores_off_good_caches_on
+ [l_chip_v_idx] +
+ g_wof->all_cores_off_iso*
+ G_oppb.iddq.good_normal_cores[quad_idx]/24;
+
+
+ // Calculate quadx_ON_cores
+ g_wof->quad_on_cores[quad_idx] =
+ (g_wof->quad_good_cores_only[quad_idx]*
+ g_wof->cores_on_per_quad[quad_idx]) /
+ G_oppb.iddq.good_normal_cores[quad_idx];
+
+
+ // Calculate quadx_BAD_OFF_cores
+ g_wof->quad_bad_off_cores[quad_idx] =
+ g_wof->all_cores_off_iso*G_oppb.iddq.good_normal_cores[quad_idx]/24;
+
+ // Reset num_cores_off_in_quad before processing current quads cores
+ uint8_t num_cores_off_in_quad = 0;
+ // Loop all cores within current quad
+ for(core_loop_idx = 0; core_loop_idx < NUM_CORES_PER_QUAD; core_loop_idx++)
+ {
+
+ if(core_powered_on(core_idx))
+ {
+
+ // Get the core temperature from TEMPPROCTHRMC sensor
+ temperature = AMECSENSOR_ARRAY_PTR(TEMPPROCTHRMC0,
+ core_idx)->sample;
+
+ // If the TEMPPROCTHRMCy is 0, use TEMPQx
+ if(temperature == 0)
+ {
+ temperature = AMECSENSOR_ARRAY_PTR(TEMPQ0,
+ quad_idx)->sample;
+ // If TEMPQx is also 0, use TEMPNEST
+ if(temperature == 0)
+ {
+ temperature = g_wof->tempnest_sense;
+ }
+ }
+
+ // Save the selected temperature
+ g_wof->tempprocthrmc[core_idx] = temperature;
+
+
+
+ // Get the difference between the temperature and tvpd_leak
+ g_wof->core_delta_temp[core_idx] =
+ g_wof->tempprocthrmc[core_idx] -
+ g_wof->tvpd_leak_on;
+
+ // Calculate the multiplier for the core
+ g_wof->core_mult[core_idx] =
+ calculate_multiplier(g_wof->core_delta_temp[core_idx]);
+
+ // For each core, incorporate core on calculation into
+ // leakage
+ idc_vdd += (g_wof->quad_on_cores[quad_idx]*
+ g_wof->core_mult[core_idx]) >> 10;
+
+ }
+ else // Core is powered off
+ {
+ // Increment the number of cores found to be off
+ num_cores_off_in_quad++;
+ }
+ // Increment the Core Index for the next iteration
+ core_idx++;
+ } // core loop
+
+ // After all cores within the current quad have been processed,
+ // incorporate calculation for cores that were off into leakage
+ idc_vdd +=
+ ((g_wof->quad_bad_off_cores[quad_idx]*g_wof->nest_mult)
+ >> 10)* num_cores_off_in_quad;
+
+ temperature = AMECSENSOR_ARRAY_PTR(TEMPQ0,
+ quad_idx)->sample;
+
+ // If TEMPQ0 is 0, use TEMPNEST
+ if( temperature == 0 )
+ {
+ temperature = g_wof->tempnest_sense;
+ }
+
+ // Save selected temperature off to amec
+ g_wof->tempq[quad_idx] = temperature;
+
+
+ // Get the quad delta temperature for cache calc
+ g_wof->quad_delta_temp[quad_idx] =
+ g_wof->tempq[quad_idx] -
+ g_wof->tvpd_leak_cache;
+
+ //Calculate the multiplier for the quad
+ g_wof->quad_mult[quad_idx] =
+ calculate_multiplier(g_wof->quad_delta_temp[quad_idx]);
+
+ // Incorporate the cache into the leakage calculation
+ idc_vdd += (l_quad_x_cache*g_wof->quad_mult[quad_idx]) >> 10;
+
+
+ }
+ } // quad loop
+ // After all Quads have been processed, incorporate calculation for quads
+ // that off into leakage
+ idc_vdd += ((g_wof->idc_quad*g_wof->nest_mult) >> 10)* num_quads_off;
+
+
+ // Finally, save the calculated leakage to amec
+ g_wof->idc_vdd = idc_vdd;
+
+}
+
+
+/**
+ * core_powered_on
+ *
+ * Description: Helper function to determine whether the given core
+ * is on based off the most recently read data from
+ * OCC-PGPE Shared SRAM
+ *
+ * Param: The desired core number
+ *
+ * Return: Returns TRUE if the core is powered on, FALSE otherwise
+ */
+inline bool core_powered_on(uint8_t i_core_num)
+{
+ return ( g_wof->core_pwr_on & (0x80000000 >> i_core_num));
+}
+
+/**
+ * num_cores_on_in_quad
+ *
+ * Description: Helper function that returns the number of cores
+ * currently powered on in the given quad based off
+ * the most recently read data from OCC-PGPE Shared SRAM
+ *
+ * Param: The Quad number
+ *
+ * Return: Returns the number of cores powered on within the given quad.
+ */
+uint8_t num_cores_on_in_quad( uint8_t i_quad_num )
+{
+ int start_index = i_quad_num * NUM_CORES_PER_QUAD;
+ int i;
+ uint8_t num_powered_on_cores = 0;
+ for(i = start_index; i < (start_index + NUM_CORES_PER_QUAD); i++)
+ {
+ if( core_powered_on(i) )
+ {
+ num_powered_on_cores++;
+ }
+ }
+
+ return num_powered_on_cores;
+}
+
+/**
+ * interpolate_linear
+ *
+ * Description: Helper function that takes in the necessary input for
+ * a linear interpolation and returns the result of the
+ * calculation
+ *
+ * Y = m*(X-x1) + y1, where m = (y2-y1) / (x2-x1)
+ *
+ * Return: The result Y of the formula above
+ */
+inline int32_t interpolate_linear( int32_t i_X,
+ int32_t i_x1,
+ int32_t i_x2,
+ int32_t i_y1,
+ int32_t i_y2 )
+{
+ return (i_X - i_x1)*((i_y2 - i_y1) / (i_x2 - i_x1)) + i_y1;
+}
+
+/**
+ * calculate_multiplier
+ *
+ * Description: This function calculates the 'm' in the formula
+ * y ~= (T*m) >> 10 by choosing the appropriate row in
+ * G_wof_iddq_mult_table based on the passed in temp, and interpolates
+ * the values of the 'm' column in order to find the appropriate multiplier
+ *
+ * Param: the delta temp between tvpd_leak and a temperature sensor. Used
+ * to find the appropriate row index into G_wof_iddq_mult_table.
+ *
+ * Return: The multiplier representing the temperature factor
+ */
+int32_t calculate_multiplier( int32_t i_temp )
+{
+ int mult_idx;
+
+ if( i_temp < G_wof_iddq_mult_table[0][0] )
+ {
+ mult_idx = 0;
+ }
+ else if( i_temp >= G_wof_iddq_mult_table[WOF_IDDQ_MULT_TABLE_N-1][0] )
+ {
+ mult_idx = WOF_IDDQ_MULT_TABLE_N - 2;
+ }
+ else
+ {
+ for(mult_idx = 0 ; mult_idx < WOF_IDDQ_MULT_TABLE_N-1; mult_idx++)
+ {
+ if( (G_wof_iddq_mult_table[mult_idx][0] <= i_temp) &&
+ (G_wof_iddq_mult_table[mult_idx+1][0] >= i_temp) )
+ {
+ break;
+ }
+ }
+ }
+
+
+ // mult index now has the row index into G_wof_iddq_mult_table.
+ // use it to calculate the final multiplier
+ return interpolate_linear( i_temp,
+ (int32_t)G_wof_iddq_mult_table[mult_idx][0],
+ (int32_t)G_wof_iddq_mult_table[mult_idx+1][0],
+ (int32_t)G_wof_iddq_mult_table[mult_idx][1],
+ (int32_t)G_wof_iddq_mult_table[mult_idx+1][1]);
+}
+
+
+
diff --git a/src/occ_405/wof/wof.h b/src/occ_405/wof/wof.h
index 4591d00..2167843 100644
--- a/src/occ_405/wof/wof.h
+++ b/src/occ_405/wof/wof.h
@@ -30,10 +30,24 @@
//******************************************************************************
// Define
//******************************************************************************
-#define MIN_BCE_REQ_SIZE 256
-#define ACTIVE_QUAD_SZ_MIN 1
-#define ACTIVE_QUAD_SZ_MAX 6
-#define WOF_HEADER_SIZE 32
+#define ACTIVE_QUAD_SZ_MIN 1
+#define ACTIVE_QUAD_SZ_MAX 6
+#define MIN_BCE_REQ_SIZE 256
+#define WOF_HEADER_SIZE 32
+#define CORE_IDDQ_MEASUREMENTS 6
+#define QUAD_POWERED_OFF 0xFF
+
+//******************************************************************************
+// Bit Vector Masks
+//******************************************************************************
+#define IVRM_STATE_QUAD_MASK 0x80
+
+//******************************************************************************
+// WOF Reason Code Masks
+//******************************************************************************
+#define WOF_RC_NO_WOF_HEADER_MASK 0x0001
+#define WOF_RC_INVALID_ACTIVE_QUADS_MASK 0x0002
+#define WOF_RC_NO_VDD_VDN_READ_MASK 0x0004
#define WOF_RC_MODE_NO_SUPPORT_MASK 0x0008
@@ -60,6 +74,77 @@ typedef struct
{
// Bit vector where each bit signifies a different failure case
uint16_t wof_disabled;
+ // Array to hold the core voltages per quad (in 100uV)
+ uint32_t v_core_100uV[MAX_NUM_QUADS];
+ // Bit vector to hold the power on status of all 24 cores
+ uint32_t core_pwr_on;
+ // Number of cores on per quad
+ uint8_t cores_on_per_quad[MAX_NUM_QUADS];
+ // The most recently read value in the sensor VOLTVDDSENSE
+ uint32_t volt_vdd_sense;
+ // The most recently read value in the sensor TEMPPROCTHRMCy where y is core num
+ uint16_t tempprocthrmc[MAX_NUM_CORES];
+ // The most recently read value in the sensor TEMPNEST
+ uint16_t tempnest_sense;
+ // The most recently read value in the sensor TEMPQx where x is the quad num
+ uint16_t tempq[MAX_NUM_QUADS];
+ // Array to hold the current 1-byte pstate values read from SRAM. 0xFF=off
+ uint8_t quad_x_pstates[MAX_NUM_QUADS];
+ // Bit vector to hold the ivrm states of the quads. 0=BYPASS, 1=REGULATION
+ uint8_t quad_ivrm_states;
+ // Contains the estimated core leakage based on temp, voltage, and vpd-leak
+ uint32_t idc_vdd;
+ // Contains the leakage current for quads
+ uint32_t idc_quad;
+ // Contains the index used for interpolation in the ALL_CORES_OFF_ISO calc
+ uint8_t voltage_idx;
+ // Contains the final calculated value of ALL_CORES_OFF_ISO
+ uint32_t all_cores_off_iso;
+ // Contains the final calculated value of ALL_CACHES_ON_ISO
+ uint32_t all_caches_on_iso;
+ // Contains good_cores_only (per_quad)
+ uint16_t quad_good_cores_only[MAX_NUM_QUADS];
+ // Contains on_cores
+ uint16_t quad_on_cores[MAX_NUM_QUADS];
+ // Contains BAD_OFF_cores
+ uint16_t quad_bad_off_cores[MAX_NUM_QUADS];
+ // Contains the multiplier(m) used in y ~=(T*m)>>10 for nest leak calc
+ uint32_t nest_mult;
+ // Contains the multiplier(m) used in y ~=(T*m)>>10 for core leak calc 0-23
+ uint32_t core_mult[MAX_NUM_CORES];
+ // Contains the multiplier(m) used in y ~=(T*m)>>10 for quad leak calc 0-5
+ uint32_t quad_mult[MAX_NUM_QUADS];
+ // Contains the delta temp used for nest leakage calc (see G_wof_iddq_mult_table)
+ // TEMPNEST - tvpd_leak_off
+ int16_t nest_delta_temp;
+ // Contains the delta temp used for core leakage calc
+ // TEMPPROCTHRMy - tvpd_leak_on (where y is the core number)
+ int16_t core_delta_temp[MAX_NUM_CORES];
+ // Contains the delta temp used for quad leakage calc
+ // TEMPQx - tvpd_leak_cache (where x is the quad number)
+ int16_t quad_delta_temp[MAX_NUM_QUADS];
+ // tvpd leak to use when either the core is off, or the entire quad is off
+ uint32_t tvpd_leak_off;
+ // tvpd leak to use when the core is on
+ uint32_t tvpd_leak_on;
+ // tvpd leak to use when performing cache calculations
+ uint32_t tvpd_leak_cache;
+ // Contains the most recently read value from SRAM for Requested active quads
+ uint8_t req_active_quad_update;
+ // Contains the previous value read from shared SRAM for requested active quads
+ uint8_t prev_req_active_quads;
+ // The current ping pong buffer SRAM address being used by PGPE
+ uint32_t curr_ping_pong_buf;
+ // The next ping pong buffer SRAM address to be used by PGPE if IPC request succeeds
+ uint32_t next_ping_pong_buf;
+ // The current vfrt address in Main Memory that WOF pulled to give to PGPE
+ uint32_t curr_vfrt_main_mem_addr;
+ // PGPE SRAM address where active_quads
+ uint32_t active_quads_sram_addr;
+ // Main Memory address where the WOF VFRT tables are located
+ uint32_t vfrt_tbls_main_mem_addr;
+ // The length of the WOF VFRT data in main memory
+ uint32_t vfrt_tbls_len;
} amec_wof_t;
typedef struct
@@ -80,7 +165,6 @@ typedef struct
uint8_t pad;
} copy_vfrt_to_sram_parms_t;
-
//******************************************************************************
// Function Prototypes
//******************************************************************************
@@ -102,8 +186,25 @@ uint32_t calc_vfrt_mainstore_addr( uint16_t i_vdd_step_from_start,
void copy_vfrt_to_sram( copy_vfrt_to_sram_parms_t * i_parms );
+void switch_ping_pong_buffer( void );
+
void send_vfrt_to_pgpe( uint32_t i_vfrt_address );
void read_shared_sram( void );
+void calculate_core_voltage( void );
+
+void calculate_core_leakage( void );
+
+inline bool core_powered_on( uint8_t i_core_num );
+
+uint8_t num_cores_on_in_quad( uint8_t i_quad_num );
+
+inline int32_t interpolate_linear( int32_t i_X,
+ int32_t i_x1,
+ int32_t i_x2,
+ int32_t i_y1,
+ int32_t i_y2 );
+
+int32_t calculate_multiplier( int32_t i_temp );
#endif
diff --git a/src/occ_405/wof/wof_service_codes.h b/src/occ_405/wof/wof_service_codes.h
index 8967580..89afb3f 100644
--- a/src/occ_405/wof/wof_service_codes.h
+++ b/src/occ_405/wof/wof_service_codes.h
@@ -32,6 +32,7 @@ enum wofModuleId
WOF_MAIN = WOF_COMP_ID | 0x01,
SEND_VFRT_TO_PGPE = WOF_COMP_ID | 0x02,
COPY_VFRT_TO_SRAM = WOF_COMP_ID | 0x03,
+ WOF_VFRT_CALLBACK = WOF_COMP_ID | 0x04,
};
OpenPOWER on IntegriCloud