diff options
Diffstat (limited to 'common/thermal.c')
-rw-r--r-- | common/thermal.c | 345 |
1 files changed, 0 insertions, 345 deletions
diff --git a/common/thermal.c b/common/thermal.c deleted file mode 100644 index e9750931be..0000000000 --- a/common/thermal.c +++ /dev/null @@ -1,345 +0,0 @@ -/* Copyright 2012 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* NEW thermal engine module for Chrome EC. This is a completely different - * implementation from the original version that shipped on Link. - */ - -#include "chipset.h" -#include "common.h" -#include "console.h" -#include "fan.h" -#include "hooks.h" -#include "host_command.h" -#include "temp_sensor.h" -#include "thermal.h" -#include "throttle_ap.h" -#include "timer.h" -#include "util.h" - -#ifdef CONFIG_ZEPHYR -#include "temp_sensor/temp_sensor.h" -#endif - -/* Console output macros */ -#define CPUTS(outstr) cputs(CC_THERMAL, outstr) -#define CPRINTS(format, args...) cprints(CC_THERMAL, format, ## args) - -/*****************************************************************************/ -/* EC-specific thermal controls */ - -test_mockable_static void smi_sensor_failure_warning(void) -{ - CPRINTS("can't read any temp sensors!"); - host_set_single_event(EC_HOST_EVENT_THERMAL); -} - -int thermal_fan_percent(int low, int high, int cur) -{ - if (cur < low) - return 0; - if (cur > high) - return 100; - return 100 * (cur - low) / (high - low); -} - -/* The logic below is hard-coded for only three thresholds: WARN, HIGH, HALT. - * This is just a validity check to be sure we catch any changes in thermal.h - */ -BUILD_ASSERT(EC_TEMP_THRESH_COUNT == 3); - -/* Keep track of which thresholds have triggered */ -static cond_t cond_hot[EC_TEMP_THRESH_COUNT]; - -/* thermal sensor read delay */ -#if defined(CONFIG_TEMP_SENSOR_POWER_GPIO) && \ - defined(CONFIG_TEMP_SENSOR_FIRST_READ_DELAY_MS) -static int first_read_delay = CONFIG_TEMP_SENSOR_FIRST_READ_DELAY_MS; -#endif - -static void thermal_control(void) -{ - int i, j, t, rv, f; - int count_over[EC_TEMP_THRESH_COUNT]; - int count_under[EC_TEMP_THRESH_COUNT]; - int num_valid_limits[EC_TEMP_THRESH_COUNT]; - int num_sensors_read; - int fmax; - int temp_fan_configured; - -#ifdef CONFIG_CUSTOM_FAN_CONTROL - int temp[TEMP_SENSOR_COUNT]; -#endif - - /* add delay to ensure thermal sensor is ready when EC boot */ -#if defined(CONFIG_TEMP_SENSOR_POWER_GPIO) && \ - defined(CONFIG_TEMP_SENSOR_FIRST_READ_DELAY_MS) - if (first_read_delay != 0) { - msleep(first_read_delay); - first_read_delay = 0; - } -#endif - - /* Get ready to count things */ - memset(count_over, 0, sizeof(count_over)); - memset(count_under, 0, sizeof(count_under)); - memset(num_valid_limits, 0, sizeof(num_valid_limits)); - num_sensors_read = 0; - fmax = 0; - temp_fan_configured = 0; - - /* go through all the sensors */ - for (i = 0; i < TEMP_SENSOR_COUNT; ++i) { - - /* read one */ - rv = temp_sensor_read(i, &t); - -#ifdef CONFIG_CUSTOM_FAN_CONTROL - /* Store all sensors value */ - temp[i] = K_TO_C(t); -#endif - - if (rv != EC_SUCCESS) - continue; - else - num_sensors_read++; - - /* check all the limits */ - for (j = 0; j < EC_TEMP_THRESH_COUNT; j++) { - int limit = thermal_params[i].temp_host[j]; - int release = thermal_params[i].temp_host_release[j]; - if (limit) { - num_valid_limits[j]++; - if (t > limit) { - count_over[j]++; - } else if (release) { - if (t < release) - count_under[j]++; - } else if (t < limit) { - count_under[j]++; - } - } - } - - /* figure out the max fan needed, too */ - if (thermal_params[i].temp_fan_off && - thermal_params[i].temp_fan_max) { - f = thermal_fan_percent(thermal_params[i].temp_fan_off, - thermal_params[i].temp_fan_max, - t); - if (f > fmax) - fmax = f; - - temp_fan_configured = 1; - } - } - - if (!num_sensors_read) { - /* - * Trigger a SMI event if we can't read any sensors. - * - * In theory we could do something more elaborate like forcing - * the system to shut down if no sensors are available after - * several retries. This is a very unlikely scenario - - * particularly on LM4-based boards, since the LM4 has its own - * internal temp sensor. It's most likely to occur during - * bringup of a new board, where we haven't debugged the I2C - * bus to the sensors; forcing a shutdown in that case would - * merely hamper board bringup. - * - * If in G3, then there is no need trigger an SMI event since - * the AP is off and this can be an expected state if - * temperature sensors are powered by a power rail that's only - * on if the AP is out of G3. Note this could be 'ANY_OFF' as - * well, but that causes the thermal unit test to fail. - */ - if (!chipset_in_state(CHIPSET_STATE_HARD_OFF)) - smi_sensor_failure_warning(); - return; - } - - /* See what the aggregated limits are. Any temp over the limit - * means it's hot, but all temps have to be under the limit to - * be cool again. - */ - for (j = 0; j < EC_TEMP_THRESH_COUNT; j++) { - if (count_over[j]) - cond_set_true(&cond_hot[j]); - else if (count_under[j] == num_valid_limits[j]) - cond_set_false(&cond_hot[j]); - } - - /* What do we do about it? (note hard-coded logic). */ - - if (cond_went_true(&cond_hot[EC_TEMP_THRESH_HALT])) { - CPRINTS("thermal SHUTDOWN"); - - /* Print temperature sensor values before shutting down AP */ - if (IS_ENABLED(CONFIG_CMD_TEMP_SENSOR)) { - console_command_temps(1, NULL); - cflush(); - } - - chipset_force_shutdown(CHIPSET_SHUTDOWN_THERMAL); - } else if (cond_went_false(&cond_hot[EC_TEMP_THRESH_HALT])) { - /* We don't reboot automatically - the user has to push - * the power button. It's likely that we can't even - * detect this sensor transition until then, but we - * do have to check in order to clear the cond_t. - */ - CPRINTS("thermal no longer shutdown"); - } - - if (cond_went_true(&cond_hot[EC_TEMP_THRESH_HIGH])) { - CPRINTS("thermal HIGH"); - throttle_ap(THROTTLE_ON, THROTTLE_HARD, THROTTLE_SRC_THERMAL); - } else if (cond_went_false(&cond_hot[EC_TEMP_THRESH_HIGH])) { - CPRINTS("thermal no longer high"); - throttle_ap(THROTTLE_OFF, THROTTLE_HARD, THROTTLE_SRC_THERMAL); - } - - if (cond_went_true(&cond_hot[EC_TEMP_THRESH_WARN])) { - CPRINTS("thermal WARN"); - throttle_ap(THROTTLE_ON, THROTTLE_SOFT, THROTTLE_SRC_THERMAL); - } else if (cond_went_false(&cond_hot[EC_TEMP_THRESH_WARN])) { - CPRINTS("thermal no longer warn"); - throttle_ap(THROTTLE_OFF, THROTTLE_SOFT, THROTTLE_SRC_THERMAL); - } - - if (temp_fan_configured) { -#ifdef CONFIG_FANS -#ifdef CONFIG_CUSTOM_FAN_CONTROL - for (i = 0; i < fan_get_count(); i++) { - if (!is_thermal_control_enabled(i)) - continue; - - board_override_fan_control(i, temp); - } -#else - /* TODO(crosbug.com/p/23797): For now, we just treat all - * fans the same. It would be better if we could assign - * different thermal profiles to each fan - in case one - * fan cools the CPU while another cools the radios or - * battery. - */ - for (i = 0; i < fan_get_count(); i++) - fan_set_percent_needed(i, fmax); -#endif -#endif - } -} - -/* Wait until after the sensors have been read */ -DECLARE_HOOK(HOOK_SECOND, thermal_control, HOOK_PRIO_TEMP_SENSOR_DONE); - -/*****************************************************************************/ -/* Console commands */ - -static int command_thermalget(int argc, char **argv) -{ - int i; - - ccprintf("sensor warn high halt fan_off fan_max name\n"); - for (i = 0; i < TEMP_SENSOR_COUNT; i++) { - ccprintf(" %2d %3d %3d %3d %3d %3d %s\n", - i, - thermal_params[i].temp_host[EC_TEMP_THRESH_WARN], - thermal_params[i].temp_host[EC_TEMP_THRESH_HIGH], - thermal_params[i].temp_host[EC_TEMP_THRESH_HALT], - thermal_params[i].temp_fan_off, - thermal_params[i].temp_fan_max, - temp_sensors[i].name); - } - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(thermalget, command_thermalget, - NULL, - "Print thermal parameters (degrees Kelvin)"); - - -static int command_thermalset(int argc, char **argv) -{ - unsigned int n; - int i, val; - char *e; - - if (argc < 3 || argc > 7) - return EC_ERROR_PARAM_COUNT; - - n = (unsigned int)strtoi(argv[1], &e, 0); - if (*e) - return EC_ERROR_PARAM1; - - for (i = 2; i < argc; i++) { - val = strtoi(argv[i], &e, 0); - if (*e) - return EC_ERROR_PARAM1 + i - 1; - if (val < 0) - continue; - switch (i) { - case 2: - thermal_params[n].temp_host[EC_TEMP_THRESH_WARN] = val; - break; - case 3: - thermal_params[n].temp_host[EC_TEMP_THRESH_HIGH] = val; - break; - case 4: - thermal_params[n].temp_host[EC_TEMP_THRESH_HALT] = val; - break; - case 5: - thermal_params[n].temp_fan_off = val; - break; - case 6: - thermal_params[n].temp_fan_max = val; - break; - } - } - - command_thermalget(0, 0); - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(thermalset, command_thermalset, - "sensor warn [high [shutdown [fan_off [fan_max]]]]", - "Set thermal parameters (degrees Kelvin)." - " Use -1 to skip."); - -/*****************************************************************************/ -/* Host commands. We'll reuse the host command number, but this is version 1, - * not version 0. Different structs, different meanings. - */ - -static enum ec_status -thermal_command_set_threshold(struct host_cmd_handler_args *args) -{ - const struct ec_params_thermal_set_threshold_v1 *p = args->params; - - if (p->sensor_num >= TEMP_SENSOR_COUNT) - return EC_RES_INVALID_PARAM; - - thermal_params[p->sensor_num] = p->cfg; - - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_THERMAL_SET_THRESHOLD, - thermal_command_set_threshold, - EC_VER_MASK(1)); - -static enum ec_status -thermal_command_get_threshold(struct host_cmd_handler_args *args) -{ - const struct ec_params_thermal_get_threshold_v1 *p = args->params; - struct ec_thermal_config *r = args->response; - - if (p->sensor_num >= TEMP_SENSOR_COUNT) - return EC_RES_INVALID_PARAM; - - *r = thermal_params[p->sensor_num]; - args->response_size = sizeof(*r); - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_THERMAL_GET_THRESHOLD, - thermal_command_get_threshold, - EC_VER_MASK(1)); |