summaryrefslogtreecommitdiffstats
path: root/src/occ/amec/amec_sensors_power.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/occ/amec/amec_sensors_power.c')
-rwxr-xr-xsrc/occ/amec/amec_sensors_power.c574
1 files changed, 574 insertions, 0 deletions
diff --git a/src/occ/amec/amec_sensors_power.c b/src/occ/amec/amec_sensors_power.c
new file mode 100755
index 0000000..5c4923f
--- /dev/null
+++ b/src/occ/amec/amec_sensors_power.c
@@ -0,0 +1,574 @@
+/******************************************************************************
+// @file amec_sensors_power.c
+// @brief AMEC Power Sensor Calculations
+*/
+/**
+ * @page ChangeLogs Change Logs
+ * @section _amec_sensors_power_c amec_sensors_power.c
+ * @verbatim
+ *
+ * Flag Def/Fea Userid Date Description
+ * -------- ---------- -------- -------- --------------------------------------
+ * thallet 02/24/2012 New file
+ * @pb00E pbavari 03/11/2012 Added correct include file
+ * @th019 835007 thallet 09/11/2012 Added power sensors
+ * @th044 892742 thallet 07/24/2013 Added module ID
+ * @ly008 894646 lychen 08/08/2013 Fix bugs in OCC handling of APSS tables for Brazos/Orlena
+ * @at016 891144 alvinwan 06/10/2013 OCC Power Cap Testing
+ * @sb000 905048 sbroyles 10/28/2013 Add tags for code cleanup,
+ * see RTC task 73327.
+ * @rt003 905677 tapiar 11/07/2013 save of proc/mem sensor data
+ * @sb001 906360 sbroyles 11/12/2013 Resolve fix tags
+ * @fk004 907588 fmkassem 11/27/2013 Add support for snapshot buffer.
+ * @gs020 909320 gjsilva 12/12/2013 Support for VR_FAN thermal control
+ * @gs021 909855 gjsilva 12/18/2013 Support for processor OT condition
+ * @gs023 912003 gjsilva 01/16/2014 Generate VRHOT signal and control loop
+ * @mw634 mware 02/09/2014 Added in call to amec_controller_centaur for stream recording
+ * @gs026 915840 gjsilva 02/13/2014 Support for Nvidia GPU power measurement
+ * @gm026 916029 milesg 02/17/2014 revert back to auto2 mode without reading GPIO's
+ * @gs027 918066 gjsilva 03/12/2014 Misc functions from ARL
+ * @gm034 920562 milesg 03/28/2014 fix voltage sensors
+ * @endverbatim
+ */
+
+/******************************************************************************/
+/* Includes */
+/******************************************************************************/
+//@pb00Ec - changed from common.h to occ_common.h for ODE support
+#include <occ_common.h>
+#include <ssx.h>
+#include <errl.h> // Error logging
+#include "sensor.h"
+#include "rtls.h"
+#include "occ_sys_config.h"
+#include "occ_service_codes.h" // for SSX_GENERIC_FAILURE
+#include "dcom.h"
+#include "proc_data.h"
+#include "amec_smh.h"
+#include "amec_slave_smh.h"
+#include <trac.h>
+#include "amec_sys.h"
+#include "sensor_enum.h"
+#include "amec_service_codes.h"
+#include <amec_sensors_power.h>
+#include <cmdh_snapshot.h> //@fk004a
+#include <vrm.h>
+#include "amec_oversub.h"
+
+// This holds the converted ADC Reads
+uint32_t G_lastValidAdcValue[MAX_APSS_ADC_CHANNELS] = {0};
+
+extern thrm_fru_data_t G_thrm_fru_data[DATA_FRU_MAX];
+
+#define ADC_CONVERTED_VALUE(i_chan) \
+ ((i_chan < MAX_APSS_ADC_CHANNELS) ? G_lastValidAdcValue[i_chan] : 0)
+
+// Function Specification
+//
+// Name: amec_sensor_from_apss_adc
+//
+// Description: Calculates sensor from raw ADC value
+//
+// Flow: FN=
+//
+// Thread: RealTime Loop
+//
+// Task Flags:
+//
+// End Function Specification
+uint32_t amec_value_from_apss_adc(uint8_t i_chan)
+{
+ uint16_t l_raw = 0;
+ uint32_t l_temp = 0;
+ uint32_t l_gain = 0;
+ uint32_t l_offset = 0;
+
+ if(i_chan != SYSCFG_INVALID_ADC_CHAN)
+ {
+ /*
+ * @sb001 Several changes made under this tag, see occ810 version 1.9
+ * for previous version.
+ * The APSS value is in mV or mA depending on the channel and the raw
+ * reading from the APSS must be decoded using the following info:
+ *
+ * APSS LSB: Vref/4096
+ * Full scale: (Vref - LSB) = 0xFFF
+ * Midscale: Vref/2 = 0x800
+ * Midscale - 1 LSB: Vref/2 - 1 LSB, 0x7FF
+ * Zero: 0V, 0x000
+ * Any voltage at or above Vref will will result in an ADC channel value
+ * of 0xFFF
+ *
+ * Our APSS has Vref pinned to 2.048 V
+ * LSB: 0.5 mV (minimum ADC resolution)
+ * Full scale: 2047.5 mV (0xFFF)
+ * Midscale: 1024 mV (0x800)
+ * Zero: 0V, 0x000
+ *
+ * To get the right mV reading from the raw APSS data all we need to do
+ * is divide the raw 12 bit ADC code by 2. The same logic applies if
+ * the channel is measuring power in mA.
+ *
+ * If there is an offset it will bein mV or mA depending upon the sensor
+ * and it needs to be added or subtracted from the raw value depending
+ * on it's signedness. Negative offsets are stored in 2's complement
+ * form.
+ *
+ * The gain values will be multiplied by 1000 in TMGT before being sent
+ * in the sysconfig packet. Raw gain from the MRW values are in A/V and
+ * TMGT will multiply this by 1000 before sending in the sysconfig
+ * packet to preserve precision. That makes the gain units mA/V.
+ *
+ * To apply the gain multiply the sysconfig value against the converted
+ * APSS voltage.
+ *
+ * Applying the gain to the converted APSS data gives (mV . mA)/V so we
+ * divide by 1000 to reduce the result to mA. This is the unit that
+ * is returned to the caller. For example:
+ * raw APSS value: 0x800
+ * converted value: raw/2 = 1024 mV
+ * gain from MRW: 10.00 A/V
+ * Converted gain: 10,000 mA/V
+ * gain adjusted output: 1024mV * 10,000 mA/V = 10,240,000 (mV . mA)/V
+ * Reduced value: adjusted/1000 = 10,240 mA
+ *
+ * Note that in the case of the remote ground and 12V sense the gain
+ * values are in V/V so the returned value is actually in mVs.
+ *
+ * Max returnable value is 4,294,967,295 mA or approx. 4.3 MA
+ */
+
+ // Get ADC Mapping calibration info for this entity.
+ l_gain = G_sysConfigData.apss_cal[i_chan].gain;
+ l_offset = G_sysConfigData.apss_cal[i_chan].offset;
+
+ // Read Raw Value in mA (divide masked channel data by 2)
+ l_raw = (G_dcom_slv_inbox_rx.adc[i_chan] & APSS_12BIT_ADC_MASK)/2;
+ // Apply offset and gain
+ if (l_offset & 0x80000000)
+ {
+ // Negative offset
+ l_raw -= (~l_offset + 1);
+ }
+ else
+ {
+ l_raw += l_offset;
+ }
+
+ l_temp = ((uint32_t)l_raw * l_gain);
+ // Reduce value back to mA or mV
+ l_temp /= 1000;
+ }
+
+ AMEC_DBG("APSS ADC info: chan=%d, raw=0x%04x, offset=%d, gain=%d calibrated output=%d\n",
+ i_chan, l_raw, l_offset, l_gain, l_temp);
+
+ return l_temp;
+}
+
+
+// Function Specification
+//
+// Name: amec_update_apss_sensors
+//
+// Description: Calculates sensor from raw ADC value
+//
+// Flow: FN=
+//
+// Thread: RealTime Loop
+//
+// Task Flags:
+//
+// End Function Specification
+void amec_update_apss_sensors(void)
+{
+ /*
+ * @sb001 Removed fake apss config data, do not reuse, the old hardcoded
+ * values will not work with the new code used in processing APSS channel
+ * data. See occ810 version 1.9 of this file for the hardcoded values that
+ * were removed.
+ * Code is in place to receive command code 0x21 SET CONFIG DATA from the
+ * FSP which should popluate the ADC and GPIO maps as well as the APSS
+ * calibration data for all 16 ADC channels.
+ */
+
+ // ------------------------------------------------------
+ // APSS Data Collection & Sensorization
+ // ------------------------------------------------------
+
+ // Need to check to make sure APSS data has been received
+ // via slave inbox first
+ if(G_slv_inbox_received)
+ {
+ uint8_t l_proc = G_pob_id.module_id;
+ uint32_t temp32 = 0;
+ uint8_t l_idx = 0;
+ uint32_t l_bulk_current_sum = 0;
+
+ // ----------------------------------------------------
+ // Convert all ADC Channels immediately
+ // ----------------------------------------------------
+ for(l_idx=0; l_idx < MAX_APSS_ADC_CHANNELS; l_idx++)
+ {
+ // These values returned are gain adjusted. The APSS readings for
+ // the remote ground and 12V sense are returned in mVs, all other
+ // readings are treated as mAs.
+ G_lastValidAdcValue[l_idx] = amec_value_from_apss_adc(l_idx);
+
+ // Add up all channels now, we will subtract ones later that don't
+ // count towards the system power
+ l_bulk_current_sum += G_lastValidAdcValue[l_idx];
+ }
+
+ // ----------------------------------------------------
+ // Convert 12Vsense into interim value - this has to happen first
+ // ----------------------------------------------------
+ uint32_t l_bulk_voltage = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.sense_12v);
+
+ // ----------------------------------------------------
+ // Convert Raw Vdd/Vcs/Vio/Vpcie Power from APSS into sensors
+ // ----------------------------------------------------
+ // Some sensor values are in Watts so after getting the mA readings we
+ // multiply by the bulk voltage (mVs) which requires us to then divide
+ // by 1000000 to get W (A.V), ie.
+ // divide by 1000 to get it back to milliUnits (0.001)
+ // divide by 10000 to get it to centiUnits (0.01)
+ // divide by 100000 to get it to deciUnits (0.1)
+ // divide by 1000000 to get it to Units (1)
+ #define ADCMULT_TO_UNITS 1000000 // @at016a
+ #define ADCMULT_ROUND ADCMULT_TO_UNITS/2 // @mw580
+ uint32_t l_vdd = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.vdd[l_proc]);
+ uint32_t l_vcs_vio_vpcie = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.vcs_vio_vpcie[l_proc]);
+ temp32 = ((l_vcs_vio_vpcie + l_vdd) * l_bulk_voltage)/ADCMULT_TO_UNITS; // @at016c
+ sensor_update(AMECSENSOR_PTR(PWR250USP0), (uint16_t) temp32);
+ // Save off the combined power from all modules
+ //@rt003a
+ for (l_idx=0; l_idx < MAX_NUM_CHIP_MODULES; l_idx++)
+ {
+ uint32_t l_vd = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.vdd[l_idx]);
+ uint32_t l_vpcie = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.vcs_vio_vpcie[l_idx]);
+ g_amec->proc_snr_pwr[l_idx] = ((l_vpcie + l_vd) * l_bulk_voltage)/ADCMULT_TO_UNITS;
+ }
+
+ // All readings from APSS come back as milliUnits, so if we want
+ // to convert one, we need to
+ // divide by 1 to get it back to milliUnits (0.001)
+ // divide by 10 to get it to centiUnits (0.01)
+ // divide by 100 to get it to deciUnits (0.1)
+ // divide by 1000 to get it to Units (1)
+ #define ADCSINGLE_TO_CENTIUNITS 100 // @mw580
+ // Vdd has both a power and a current sensor, we convert the Vdd power
+ // to Watts and the current to centiAmps
+ temp32 = ((l_vdd * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; // @at016c @mw580
+ sensor_update( AMECSENSOR_PTR(PWR250USVDD0), (uint16_t)temp32);
+ temp32 = (l_vdd)/ADCSINGLE_TO_CENTIUNITS; // Current is in 0.01 Amps,
+ sensor_update( AMECSENSOR_PTR(CUR250USVDD0), l_vdd);
+ temp32 = ((l_vcs_vio_vpcie * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; // @at016c @mw580
+ sensor_update( AMECSENSOR_PTR(PWR250USVCS0), (uint16_t)temp32);
+
+ // ----------------------------------------------------
+ // Convert Other Raw Misc Power from APSS into sensors
+ // ----------------------------------------------------
+
+ // Fans
+ temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.fans[0]);
+ temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.fans[1]);
+ temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; // @at016c @mw580
+ sensor_update( AMECSENSOR_PTR(PWR250USFAN), (uint16_t)temp32);
+
+ // I/O
+ temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.io[0]);
+ temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.io[1]);
+ temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.io[2]);
+ temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; // @at016c @mw580
+ sensor_update( AMECSENSOR_PTR(PWR250USIO), (uint16_t)temp32);
+
+ // Memory
+ temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_proc]);
+ temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; // @at016c @mw580
+ sensor_update( AMECSENSOR_PTR(PWR250USMEM0), (uint16_t)temp32);
+ // Save off the combined power from all memory
+ //@rt003a
+ for (l_idx=0; l_idx < MAX_NUM_CHIP_MODULES; l_idx++)
+ {
+ uint32_t l_temp = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.memory[l_idx]);
+ g_amec->mem_snr_pwr[l_idx] = ((l_temp * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; // @mw580
+ }
+
+ // Storage/Media
+ temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.storage_media[0]);
+ temp32 += ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.storage_media[1]);
+ temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; // @at016c @mw580
+ sensor_update( AMECSENSOR_PTR(PWR250USSTORE), (uint16_t)temp32);
+
+ // GPU adapter
+ temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.gpu);
+ temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS;
+ sensor_update( AMECSENSOR_PTR(PWR250USGPU), (uint16_t)temp32);
+
+ // ----------------------------------------------------
+ // Convert Raw Bulk Power from APSS into sensors
+ // ----------------------------------------------------
+ // We don't get this adc channel in Tuleta, we have to add it manually.
+ // With valid sysconfig data the code here should automatically use what
+ // is provided by the APSS if it is available, or manually sum it up if not.
+ temp32 = ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.total_current_12v);
+ temp32 = ((temp32 * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; // @at016c @mw580
+
+ // To calculated the total 12V current based on a sum of all ADC channels,
+ // Subract adc channels that don't measure power
+ l_bulk_current_sum -= ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.sense_12v);
+ l_bulk_current_sum -= ADC_CONVERTED_VALUE(G_sysConfigData.apss_adc_map.remote_gnd);
+
+ // If we don't have a ADC channel that measures the bulk 12v power, use
+ // the ADC sum instead
+ if(0 == temp32)
+ {
+ temp32 = ((l_bulk_current_sum * l_bulk_voltage)+ADCMULT_ROUND)/ADCMULT_TO_UNITS; // @at016c @mw580
+ }
+ sensor_update(AMECSENSOR_PTR(PWR250US), (uint16_t)temp32);
+
+ //@fk004a - Calculate average frequency of all OCCs.
+ uint32_t l_allOccAvgFreqOver250us = 0;
+ uint8_t l_presentOCCs = 0;
+ uint8_t l_occCount = 0;
+
+ // Add up the average freq from all OCCs.
+ for (l_occCount = 0; l_occCount < MAX_OCCS; l_occCount++)
+ {
+ if (G_sysConfigData.is_occ_present & (1<< l_occCount))
+ {
+ l_allOccAvgFreqOver250us += G_dcom_slv_outbox_rx[l_occCount].freqa2msp0;
+ l_presentOCCs++;
+ }
+ }
+ //Calculate average of all the OCCs.
+ l_allOccAvgFreqOver250us /= l_presentOCCs;
+
+ // @fk004a
+ // Save the max and min pwr250us sensors and keep
+ // an accumulator of the average frequency over 30 seconds.
+ if (g_pwr250us_over30sec.count == 0)
+ {
+ //The counter has been reset, therefore initialize the stored values.
+ g_pwr250us_over30sec.max = (uint16_t) temp32;
+ g_pwr250us_over30sec.min = (uint16_t) temp32;
+ g_pwr250us_over30sec.freqaAccum = l_allOccAvgFreqOver250us;
+
+ }
+ else
+ {
+ //Check for max.
+ if (temp32 > g_pwr250us_over30sec.max)
+ {
+ g_pwr250us_over30sec.max = (uint16_t) temp32;
+ }
+ //Check for min.
+ if (temp32 < g_pwr250us_over30sec.min)
+ {
+ g_pwr250us_over30sec.min = (uint16_t) temp32;
+ }
+ //Average frequency accumulator.
+ g_pwr250us_over30sec.freqaAccum += l_allOccAvgFreqOver250us;
+
+ }
+
+ //Count of number of updates.
+ g_pwr250us_over30sec.count++;
+
+ // ----------------------------------------------------
+ // Clear Flag to indicate that AMEC has received the data.
+ // ----------------------------------------------------
+ G_slv_inbox_received = FALSE;
+ }
+ else
+ {
+ // Skip it...AMEC Health Monitor will figure out we didn't
+ // update this sensor.
+ }
+}
+
+
+// Function Specification
+//
+// Name: amec_update_vrm_sensors
+//
+// Description: Updates sensors that use data from the VRMs
+// (e.g., VR_FAN, FANS_FULL_SPEED, VR_HOT).
+//
+// Flow: FN=
+//
+// Thread: RealTime Loop
+//
+// Task Flags:
+//
+// End Function Specification
+void amec_update_vrm_sensors(void)
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ int l_rc = 0;
+ int l_vrfan = 0;
+ int l_softoc = 0;
+ int l_minus_np1_regmode = 0;
+ int l_minus_n_regmode = 0;
+ static uint8_t L_error_count = 0;
+ uint8_t l_pin = 0;
+ uint8_t l_pin_value = 1; // active low, so set default to high
+ uint8_t l_vrhot_count = 0;
+ errlHndl_t l_err = NULL;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+
+ // Check if we have access to SPIVID. In DCMs only Master OCC has access to
+ // the SPIVID.
+ if (G_dcm_occ_role == OCC_DCM_MASTER)
+ {
+ // VR_FAN and SOFT_OC come from SPIVID
+ l_rc = vrm_read_state(SPIVRM_PORT(0),
+ &l_minus_np1_regmode,
+ &l_minus_n_regmode,
+ &l_vrfan,
+ &l_softoc);
+
+ if (l_rc == 0)
+ {
+ // Update the VR_FAN sensor
+ sensor_update( AMECSENSOR_PTR(VRFAN250USPROC), (uint16_t)l_vrfan );
+
+ // Clear our error count and the 'read failure' flag (since we can
+ // read VR_FAN signal)
+ L_error_count = 0;
+ G_thrm_fru_data[DATA_FRU_VRM].read_failure = 0;
+
+ // Obtain the 'fan_full_speed' GPIO from APSS
+ l_pin = G_sysConfigData.apss_gpio_map.fans_full_speed;
+
+ // No longer reading gpio from APSS in GA1 due to instability in APSS composite mode -- gm026
+ //apss_gpio_get(l_pin, &l_pin_value);
+
+ // VR_HOT sensor is a counter of number of times the VRHOT signal
+ // has been asserted
+ l_vrhot_count = AMECSENSOR_PTR(VRHOT250USPROC)->sample;
+
+ // Check if VR_FAN is asserted AND if 'fans_full_speed' GPIO is ON.
+ // Note that this GPIO is active low.
+ if (AMECSENSOR_PTR(VRFAN250USPROC)->sample && !(l_pin_value))
+ {
+ // VR_FAN is asserted and 'fans_full_speed' GPIO is ON,
+ // then increment our VR_HOT counter
+ if (l_vrhot_count < g_amec->vrhotproc.setpoint)
+ {
+ l_vrhot_count++;
+ }
+ }
+ else
+ {
+ // Reset our VR_HOT counter
+ l_vrhot_count = 0;
+ }
+ sensor_update(AMECSENSOR_PTR(VRHOT250USPROC), l_vrhot_count);
+ }
+ else
+ {
+ // Increment our error count
+ L_error_count++;
+
+ // Don't allow the error count to wrap
+ if (L_error_count == 0)
+ {
+ L_error_count = 0xFF;
+ }
+
+ // Log an error if we exceeded our number of fail-to-read sensor
+ if ((L_error_count == g_amec->proc[0].vrfan_error_count) &&
+ (g_amec->proc[0].vrfan_error_count != 0xFF))
+ {
+ TRAC_ERR("amec_update_vrm_sensors: Failed to read VR_FAN for %u consecutive times!",
+ L_error_count);
+
+ // Also, inform the thermal thread to send a cooling request
+ G_thrm_fru_data[DATA_FRU_VRM].read_failure = 1;
+
+ /* @
+ * @errortype
+ * @moduleid AMEC_HEALTH_CHECK_VRFAN_TIMEOUT
+ * @reasoncode VRM_VRFAN_TIMEOUT
+ * @userdata1 timeout value
+ * @userdata2 0
+ * @userdata4 OCC_NO_EXTENDED_RC
+ * @devdesc Failed to read VR_FAN signal from regulator.
+ *
+ */
+ l_err = createErrl(AMEC_HEALTH_CHECK_VRFAN_TIMEOUT, //modId
+ VRM_VRFAN_TIMEOUT, //reasoncode
+ OCC_NO_EXTENDED_RC, //Extended reason code
+ ERRL_SEV_PREDICTIVE, //Severity
+ NULL, //Trace Buf
+ DEFAULT_TRACE_SIZE, //Trace Size
+ g_amec->thermaldimm.temp_timeout, //userdata1
+ 0); //userdata2
+
+ // Callout backplane for this VRM error
+ addCalloutToErrl(l_err,
+ ERRL_CALLOUT_TYPE_HUID,
+ G_sysConfigData.backplane_huid,
+ ERRL_CALLOUT_PRIORITY_MED);
+
+ // Commit the error
+ commitErrl(&l_err);
+ }
+ }
+ }
+
+ if( 1 )
+ {
+ sensor_update( AMECSENSOR_PTR(VRFAN250USMEM), 0 );
+ sensor_update( AMECSENSOR_PTR(VRHOT250USMEM), 0 );
+ }
+}
+
+// Function Specification
+//
+// Name: amec_update_external_voltage
+//
+// Description: Measure actual external voltage
+//
+//
+// Flow: FN=
+//
+// Thread: RealTime Loop
+//
+// Task Flags:
+//
+// End Function Specification
+void amec_update_external_voltage()
+{
+ /*------------------------------------------------------------------------*/
+ /* Local Variables */
+ /*------------------------------------------------------------------------*/
+ uint32_t l_data = 0;
+ uint16_t l_temp = 0;
+ uint16_t l_vdd = 0;
+ uint16_t l_vcs = 0;
+
+ /*------------------------------------------------------------------------*/
+ /* Code */
+ /*------------------------------------------------------------------------*/
+ // Collect the external voltage data
+ l_data = in32(PMC_GLOBAL_ACTUAL_VOLTAGE_REG); //gm034 (at malcolm's request)
+
+ // Extract the Vdd vid code and convert to voltage
+ l_temp = (l_data & 0xFF000000) >>24;
+ l_vdd = 16125 - ((uint32_t)l_temp * 625)/10;
+
+ // Extract the Vcs vid code and convert to voltage
+ l_temp = (l_data & 0x00FF0000) >>16;
+ l_vcs = 16125 - ((uint32_t)l_temp * 625)/10;
+
+ sensor_update( AMECSENSOR_PTR(VOLT250USP0V0), (uint16_t) l_vdd);
+ sensor_update( AMECSENSOR_PTR(VOLT250USP0V1), (uint16_t) l_vcs);
+}
OpenPOWER on IntegriCloud