diff options
-rw-r--r-- | board/link/board_thermal.c | 37 | ||||
-rw-r--r-- | board/link/build.mk | 1 | ||||
-rw-r--r-- | board/link/ec.tasklist | 1 | ||||
-rw-r--r-- | common/build.mk | 1 | ||||
-rw-r--r-- | common/thermal.c | 195 | ||||
-rw-r--r-- | include/thermal.h | 50 |
6 files changed, 285 insertions, 0 deletions
diff --git a/board/link/board_thermal.c b/board/link/board_thermal.c new file mode 100644 index 0000000000..4b96f1f5f5 --- /dev/null +++ b/board/link/board_thermal.c @@ -0,0 +1,37 @@ +/* Copyright (c) 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. + */ + +/* Link-specific thermal configuration module for Chrome EC */ + +#include "thermal.h" +#include "board.h" + +struct thermal_config_t thermal_config[TEMP_SENSOR_COUNT] = { + /* I2C_CPU-Die */ + {THERMAL_CONFIG_NEED_VS, {THERMAL_THRESHOLD_DISABLE_ALL}}, + /* I2C_CPU-Object */ + {THERMAL_CONFIG_NEED_VS, {313, 323, 343, 353, 358}}, + /* I2C_PCH-Die */ + {THERMAL_CONFIG_NEED_VS, {THERMAL_THRESHOLD_DISABLE_ALL}}, + /* I2C_PCH-Object */ + {THERMAL_CONFIG_NEED_VS, {THERMAL_THRESHOLD_DISABLE, + THERMAL_THRESHOLD_DISABLE, 343, THERMAL_THRESHOLD_DISABLE, 358}}, + /* I2C_DDR-Die */ + {THERMAL_CONFIG_NEED_VS, {THERMAL_THRESHOLD_DISABLE_ALL}}, + /* I2C_DDR-Object */ + {THERMAL_CONFIG_NEED_VS, {THERMAL_THRESHOLD_DISABLE, + THERMAL_THRESHOLD_DISABLE, 343, THERMAL_THRESHOLD_DISABLE, 358}}, + /* I2C_Charger-Die */ + {THERMAL_CONFIG_NEED_VS, {THERMAL_THRESHOLD_DISABLE_ALL}}, + /* I2C_Charger-Object */ + {THERMAL_CONFIG_NEED_VS, {THERMAL_THRESHOLD_DISABLE, + THERMAL_THRESHOLD_DISABLE, 343, THERMAL_THRESHOLD_DISABLE, 358}}, + /* ECInternal */ + {THERMAL_CONFIG_NO_FLAG, {THERMAL_THRESHOLD_DISABLE, + THERMAL_THRESHOLD_DISABLE, 343, THERMAL_THRESHOLD_DISABLE, 373}}, + /* PECI */ + {THERMAL_CONFIG_WARNING_ON_FAIL | THERMAL_CONFIG_NEED_CPU, + {328, 338, 343, 348, 353}}, +}; diff --git a/board/link/build.mk b/board/link/build.mk index b600d69d13..97595996d9 100644 --- a/board/link/build.mk +++ b/board/link/build.mk @@ -10,3 +10,4 @@ CHIP:=lm4 board-y=board.o board-$(CONFIG_TEMP_SENSOR)+=board_temp_sensor.o +board-$(CONFIG_TASK_THERMAL)+=board_thermal.o diff --git a/board/link/ec.tasklist b/board/link/ec.tasklist index a8a05c24ea..a2d83316af 100644 --- a/board/link/ec.tasklist +++ b/board/link/ec.tasklist @@ -16,6 +16,7 @@ #define CONFIG_TASK_LIST \ TASK(WATCHDOG, watchdog_task, NULL) \ TASK(TEMPSENSOR, temp_sensor_task, NULL) \ + TASK(THERMAL, thermal_task, NULL) \ TASK(PWM, pwm_task, NULL) \ TASK(KEYSCAN, keyboard_scan_task, NULL) \ TASK(POWERBTN, power_button_task, NULL) \ diff --git a/common/build.mk b/common/build.mk index 34952d410b..649fe9b6d9 100644 --- a/common/build.mk +++ b/common/build.mk @@ -16,6 +16,7 @@ common-$(CONFIG_TASK_GAIAPOWER)+=gaia_power.o common-$(CONFIG_FLASH)+=flash_commands.o common-$(CONFIG_PSTORE)+=pstore_commands.o common-$(CONFIG_PWM)+=pwm_commands.o +common-$(CONFIG_TASK_THERMAL)+=thermal.o common-$(CONFIG_TEMP_SENSOR)+=temp_sensor.o common-$(CONFIG_TMP006)+=tmp006.o common-$(CONFIG_LIGHTBAR)+=leds.o diff --git a/common/thermal.c b/common/thermal.c new file mode 100644 index 0000000000..ffcd0986fd --- /dev/null +++ b/common/thermal.c @@ -0,0 +1,195 @@ +/* Copyright (c) 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. + */ + +/* Thermal engine module for Chrome EC */ + +#include "board.h" +#include "console.h" +#include "gpio.h" +#include "pwm.h" +#include "task.h" +#include "temp_sensor.h" +#include "thermal.h" +#include "uart.h" +#include "util.h" +#include "x86_power.h" + +/* Defined in board_thermal.c. Must be in the same order + * as in enum temp_sensor_id. */ +extern struct thermal_config_t thermal_config[TEMP_SENSOR_COUNT]; + +/* Number of consecutive overheated events for each temperature sensor. */ +static int8_t ot_count[TEMP_SENSOR_COUNT][THRESHOLD_COUNT]; + +/* Flag that indicate if each threshold is reached. + * Note that higher threshold reached does not necessarily mean lower thresholds + * are reached (since we can disable any threshold.) */ +static int8_t overheated[THRESHOLD_COUNT]; + + +static void smi_overheated_warning(void) +{ + /* TODO: crosbug.com/p/8249 */ +} + + +static void smi_sensor_failure_warning(void) +{ + /* TODO: crosbug.com/p/8249 */ +} + + +static void overheated_action(void) +{ + if (overheated[THRESHOLD_POWER_DOWN]) { + x86_power_force_shutdown(); + return; + } + + if (overheated[THRESHOLD_CPU_DOWN]) + x86_power_cpu_overheated(1); + else { + x86_power_cpu_overheated(0); + if (overheated[THRESHOLD_WARNING]) + smi_overheated_warning(); + } + + if (overheated[THRESHOLD_FAN_HI]) + pwm_set_fan_target_rpm(-1); /* Max RPM. */ + else if (overheated[THRESHOLD_FAN_LO]) + pwm_set_fan_target_rpm(6000); + else + pwm_set_fan_target_rpm(0); +} + + +/* Update counter and check if the counter has reached delay limit. + * Note that we have 10 seconds delay to prevent one error value triggering + * overheated action. */ +static inline void update_and_check_stat(int temp, + int sensor_id, + int threshold_id) +{ + const struct thermal_config_t *config = thermal_config + sensor_id; + const int16_t threshold = config->thresholds[threshold_id]; + + if (threshold > 0 && temp >= threshold) { + ++ot_count[sensor_id][threshold_id]; + if (ot_count[sensor_id][threshold_id] >= 10) { + ot_count[sensor_id][threshold_id] = 10; + overheated[threshold_id] = 1; + } + } + else + ot_count[sensor_id][threshold_id] = 0; +} + + +static void thermal_process(void) +{ + int i, j; + int cur_temp; + + for (i = 0; i < THRESHOLD_COUNT; ++i) + overheated[i] = 0; + + for (i = 0; i < TEMP_SENSOR_COUNT; ++i) { + int flag = thermal_config[i].config_flags; + + if (flag & THERMAL_CONFIG_NEED_VS && + gpio_get_level(GPIO_PGOOD_1_8VS) == 0) + continue; + + if (flag & THERMAL_CONFIG_NEED_CPU && + x86_power_in_S0() == 0) + continue; + + cur_temp = temp_sensor_read(i); + /* Sensor failure. */ + /* TODO: PECI temperature sensor is currently flaky and thus + * sensor failure is now ignored. Change this when we have + * reliable PECI temperature sensor. */ + if (cur_temp == -1) { + if (flag & THERMAL_CONFIG_WARNING_ON_FAIL) + smi_sensor_failure_warning(); + continue; + } + for (j = 0; j < THRESHOLD_COUNT; ++j) + update_and_check_stat(cur_temp, i, j); + } + + overheated_action(); +} + + +void thermal_task(void) +{ + while (1) { + thermal_process(); + /* Wait 1s */ + task_wait_msg(1000000); + } +} + +/*****************************************************************************/ +/* Console commands */ + +static void print_thermal_config(int sensor_id) +{ + const struct thermal_config_t *config = thermal_config + sensor_id; + uart_printf("Sensor %d:\n", sensor_id); + uart_printf("\tFan Low: %d K \n", + config->thresholds[THRESHOLD_FAN_LO]); + uart_printf("\tFan High: %d K \n", + config->thresholds[THRESHOLD_FAN_HI]); + uart_printf("\tWarning: %d K \n", + config->thresholds[THRESHOLD_WARNING]); + uart_printf("\tCPU Down: %d K \n", + config->thresholds[THRESHOLD_CPU_DOWN]); + uart_printf("\tPower Down: %d K \n", + config->thresholds[THRESHOLD_POWER_DOWN]); +} + + +static int command_thermal_config(int argc, char **argv) +{ + char *e; + int sensor_id, threshold_id, value; + + if (argc != 2 && argc != 4) { + uart_puts("Usage: thermal <sensor> [<threshold_id> <value>]\n"); + return EC_ERROR_UNKNOWN; + } + + sensor_id = strtoi(argv[1], &e, 0); + if ((e && *e) || sensor_id < 0 || sensor_id >= TEMP_SENSOR_COUNT) { + uart_puts("Bad sensor ID.\n"); + return EC_ERROR_UNKNOWN; + } + + if (argc == 2) { + print_thermal_config(sensor_id); + return EC_SUCCESS; + } + + threshold_id = strtoi(argv[2], &e, 0); + if ((e && *e) || threshold_id < 0 || threshold_id >= THRESHOLD_COUNT) { + uart_puts("Bad threshold ID.\n"); + return EC_ERROR_UNKNOWN; + } + + value = strtoi(argv[3], &e, 0); + if ((e && *e) || value < 0) { + uart_puts("Bad threshold value.\n"); + return EC_ERROR_UNKNOWN; + } + + thermal_config[sensor_id].thresholds[threshold_id] = value; + uart_printf("Setting threshold %d of sensor %d to %d\n", + threshold_id, sensor_id, value); + + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(thermal, command_thermal_config); diff --git a/include/thermal.h b/include/thermal.h new file mode 100644 index 0000000000..aa6cc08f4f --- /dev/null +++ b/include/thermal.h @@ -0,0 +1,50 @@ +/* Copyright (c) 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. + */ + +/* Thermal engine module for Chrome EC */ + +#ifndef __CROS_EC_THERMAL_H +#define __CROS_EC_THERMAL_H + +#include "util.h" + +#define THERMAL_CONFIG_NO_FLAG 0x0 +#define THERMAL_CONFIG_WARNING_ON_FAIL 0x1 +#define THERMAL_CONFIG_NEED_VS 0x2 +#define THERMAL_CONFIG_NEED_CPU 0x4 + +/* Set a threshold temperature to this value to disable the threshold limit. */ +#define THERMAL_THRESHOLD_DISABLE 0 + +/* This macro is used to disable all threshold for a sensor. + * The value 0 expands to all field in the array 'thresholds'. Change this + * if THERMAL_THRESHOLD_DISABLE is no longer 0. + */ +#define THERMAL_THRESHOLD_DISABLE_ALL 0 + +enum thermal_threshold { + /* Low fan speed */ + THRESHOLD_FAN_LO = 0, + /* High fan speed */ + THRESHOLD_FAN_HI, + /* Issue overheating warning */ + THRESHOLD_WARNING, + /* Shut down CPU */ + THRESHOLD_CPU_DOWN, + /* Shut down everything we can */ + THRESHOLD_POWER_DOWN, + + THRESHOLD_COUNT +}; + +/* Configuration for temperature sensor. Temperature value in degree K. */ +struct thermal_config_t { + /* Configuration flags. */ + int8_t config_flags; + /* Threshold temperatures. */ + int16_t thresholds[THRESHOLD_COUNT]; +}; + +#endif /* __CROS_EC_THERMAL_H */ |