diff --git a/src/occ_405/amec/amec_parm.h b/src/occ_405/amec/amec_parm.h index 83104f9a..43a44622 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 cbd994da..bcc70598 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 2c7e90bb..8afaf67c 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 #include "p9_pstates_occ.h" +#include #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 688be991..07793193 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 c55194f4..beb46b5c 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 b459b447..f6a5b4ab 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 e185e7b9..e74d843a 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 b0f74576..08a204ba 100644 --- a/src/occ_405/wof/wof.c +++ b/src/occ_405/wof/wof.c @@ -31,34 +31,71 @@ #include #include #include +#include +#include #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 *)(¤t_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 4591d006..21678437 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 8967580e..89afb3ff 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, };