summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVic Yang <victoryang@chromium.org>2012-02-27 13:41:32 -0800
committerVic Yang <victoryang@chromium.org>2012-02-28 16:51:54 -0800
commit13b5c41951c2da3e90ac115a3dbe8aaddb959782 (patch)
tree60737feac456fc38c591d8d209b295fe7fcaa660
parentb2b5455f327804bd1f72b3c617745fd5c5ca086b (diff)
downloadchrome-ec-13b5c41951c2da3e90ac115a3dbe8aaddb959782.tar.gz
Thermal Engine
The thermal engine monitors the temperature readings from all sensors. For each sensor, five threshold temperatures can be set: 1. Low fan speed. 2. High fan speed. 3. SMI warning. 4. Shutdown CPU. 5. Shutdown everything we can. Each of these thresholds can be set to either a fixed value or disabled. Currently the real implementation of SMI warning and shutting down is left as TODO, as indicated in the comment. Signed-off-by: Vic Yang <victoryang@chromium.org> BUG=chrome-os-partner:8250 TEST=Manually change threshold value to test all actions can be triggered. Change-Id: If168dcff78ef2d7a3203cb227e1739a08eca961e
-rw-r--r--board/link/board_thermal.c37
-rw-r--r--board/link/build.mk1
-rw-r--r--board/link/ec.tasklist1
-rw-r--r--common/build.mk1
-rw-r--r--common/thermal.c195
-rw-r--r--include/thermal.h50
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 */