summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/acpi.c6
-rw-r--r--common/build.mk1
-rw-r--r--common/dptf.c188
-rw-r--r--common/temp_sensor.c2
-rw-r--r--common/thermal.c129
-rw-r--r--include/config.h17
-rw-r--r--include/console_channel.inc3
7 files changed, 214 insertions, 132 deletions
diff --git a/common/acpi.c b/common/acpi.c
index 58bb658a84..f4aba3af9b 100644
--- a/common/acpi.c
+++ b/common/acpi.c
@@ -29,7 +29,7 @@ static int __bss_slow acpi_data_count;
/* Test byte in ACPI memory space */
static uint8_t __bss_slow acpi_mem_test;
-#ifdef CONFIG_TEMP_SENSOR
+#ifdef CONFIG_DPTF
static int __bss_slow dptf_temp_sensor_id; /* last sensor ID written */
static int __bss_slow dptf_temp_threshold; /* last threshold written */
#endif
@@ -153,7 +153,7 @@ int acpi_ap_to_ec(int is_cmd, uint8_t value, uint8_t *resultptr)
result = dptf_get_fan_duty_target();
break;
#endif
-#ifdef CONFIG_TEMP_SENSOR
+#ifdef CONFIG_DPTF
case EC_ACPI_MEM_TEMP_ID:
result = dptf_query_next_sensor_event();
break;
@@ -198,7 +198,7 @@ int acpi_ap_to_ec(int is_cmd, uint8_t value, uint8_t *resultptr)
dptf_set_fan_duty_target(data);
break;
#endif
-#ifdef CONFIG_TEMP_SENSOR
+#ifdef CONFIG_DPTF
case EC_ACPI_MEM_TEMP_ID:
dptf_temp_sensor_id = data;
break;
diff --git a/common/build.mk b/common/build.mk
index 1163699960..2e0eb3e946 100644
--- a/common/build.mk
+++ b/common/build.mk
@@ -40,6 +40,7 @@ common-$(CONFIG_COMMON_RUNTIME)+=hooks.o main.o system.o shared_mem.o
common-$(CONFIG_COMMON_TIMER)+=timer.o
common-$(CONFIG_CRC8)+= crc8.o
common-$(CONFIG_DEVICE_STATE)+=device_state.o
+common-$(CONFIG_DPTF)+=dptf.o
common-$(CONFIG_EXTENSION_COMMAND)+=extension.o
common-$(CONFIG_EXTPOWER_GPIO)+=extpower_gpio.o
common-$(CONFIG_FANS)+=fan.o pwm.o
diff --git a/common/dptf.c b/common/dptf.c
new file mode 100644
index 0000000000..638427c3b3
--- /dev/null
+++ b/common/dptf.c
@@ -0,0 +1,188 @@
+/* Copyright 2016 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.
+ */
+
+#include "atomic.h"
+#include "common.h"
+#include "console.h"
+#include "dptf.h"
+#include "hooks.h"
+#include "host_command.h"
+#include "temp_sensor.h"
+#include "util.h"
+
+/* Console output macros */
+#define CPUTS(outstr) cputs(CC_DPTF, outstr)
+#define CPRINTS(format, args...) cprints(CC_DPTF, format, ## args)
+
+/*****************************************************************************/
+/* DPTF temperature thresholds */
+
+static struct {
+ int temp; /* degrees K, negative for disabled */
+ cond_t over; /* watch for crossings */
+} dptf_threshold[TEMP_SENSOR_COUNT][DPTF_THRESHOLDS_PER_SENSOR];
+
+static void dptf_init(void)
+{
+ int id, t;
+
+ for (id = 0; id < TEMP_SENSOR_COUNT; id++)
+ for (t = 0; t < DPTF_THRESHOLDS_PER_SENSOR; t++) {
+ dptf_threshold[id][t].temp = -1;
+ cond_init(&dptf_threshold[id][t].over, 0);
+ }
+
+}
+DECLARE_HOOK(HOOK_INIT, dptf_init, HOOK_PRIO_DEFAULT);
+
+/* Keep track of which triggered sensor thresholds the AP has seen */
+static uint32_t dptf_seen;
+
+int dptf_query_next_sensor_event(void)
+{
+ int id;
+
+ for (id = 0; id < TEMP_SENSOR_COUNT; id++)
+ if (dptf_seen & (1 << id)) { /* atomic? */
+ atomic_clear(&dptf_seen, (1 << id));
+ return id;
+ }
+
+ return -1;
+}
+
+/* Return true if any threshold transition occurs. */
+static int dpft_check_temp_threshold(int sensor_id, int temp)
+{
+ int tripped = 0;
+ int max, i;
+
+ for (i = 0; i < DPTF_THRESHOLDS_PER_SENSOR; i++) {
+
+ max = dptf_threshold[sensor_id][i].temp;
+ if (max < 0) /* disabled? */
+ continue;
+
+ if (temp >= max)
+ cond_set_true(&dptf_threshold[sensor_id][i].over);
+ else if (temp <= max - DPTF_THRESHOLD_HYSTERESIS)
+ cond_set_false(&dptf_threshold[sensor_id][i].over);
+
+ if (cond_went_true(&dptf_threshold[sensor_id][i].over)) {
+ CPRINTS("DPTF over threshold [%d][%d",
+ sensor_id, i);
+ atomic_or(&dptf_seen, (1 << sensor_id));
+ tripped = 1;
+ }
+ if (cond_went_false(&dptf_threshold[sensor_id][i].over)) {
+ CPRINTS("DPTF under threshold [%d][%d",
+ sensor_id, i);
+ atomic_or(&dptf_seen, (1 << sensor_id));
+ tripped = 1;
+ }
+ }
+
+ return tripped;
+}
+
+void dptf_set_temp_threshold(int sensor_id, int temp, int idx, int enable)
+{
+ CPRINTS("DPTF sensor %d, threshold %d C, index %d, %sabled",
+ sensor_id, K_TO_C(temp), idx, enable ? "en" : "dis");
+
+ if (enable) {
+ /* Don't update threshold condition if already enabled */
+ if (dptf_threshold[sensor_id][idx].temp == -1)
+ cond_init(&dptf_threshold[sensor_id][idx].over, 0);
+ dptf_threshold[sensor_id][idx].temp = temp;
+ atomic_clear(&dptf_seen, (1 << sensor_id));
+ } else {
+ dptf_threshold[sensor_id][idx].temp = -1;
+ }
+}
+
+/*****************************************************************************/
+/* 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);
+}
+
+static void thermal_control_dptf(void)
+{
+ int i, t, rv;
+ int dptf_tripped;
+ int num_sensors_read;
+
+ dptf_tripped = 0;
+ num_sensors_read = 0;
+
+ /* go through all the sensors */
+ for (i = 0; i < TEMP_SENSOR_COUNT; ++i) {
+ rv = temp_sensor_read(i, &t);
+ if (rv != EC_SUCCESS)
+ continue;
+ else
+ num_sensors_read++;
+ /* and check the dptf thresholds */
+ dptf_tripped |= dpft_check_temp_threshold(i, t);
+ }
+
+ 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.
+ */
+ smi_sensor_failure_warning();
+ }
+
+ /* Don't forget to signal any DPTF thresholds */
+ if (dptf_tripped)
+ host_set_single_event(EC_HOST_EVENT_THERMAL_THRESHOLD);
+}
+
+/* Wait until after the sensors have been read */
+DECLARE_HOOK(HOOK_SECOND, thermal_control_dptf, HOOK_PRIO_TEMP_SENSOR_DONE);
+
+/*****************************************************************************/
+/* Console commands */
+
+static int command_dptftemp(int argc, char **argv)
+{
+ int id, t;
+ int temp, trig;
+
+ ccprintf("sensor thresh0 thresh1\n");
+ for (id = 0; id < TEMP_SENSOR_COUNT; id++) {
+ ccprintf(" %2d", id);
+ for (t = 0; t < DPTF_THRESHOLDS_PER_SENSOR; t++) {
+ temp = dptf_threshold[id][t].temp;
+ trig = cond_is_true(&dptf_threshold[id][t].over);
+ if (temp < 0)
+ ccprintf(" --- ");
+ else
+ ccprintf(" %3d%c", temp,
+ trig ? '*' : ' ');
+ }
+ ccprintf(" %s\n", temp_sensors[id].name);
+ }
+
+ ccprintf("AP seen mask: 0x%08x\n", dptf_seen);
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(dptftemp, command_dptftemp,
+ NULL,
+ "Print DPTF thermal parameters (degrees Kelvin)",
+ NULL);
diff --git a/common/temp_sensor.c b/common/temp_sensor.c
index 4f1a8d7701..7586fa9945 100644
--- a/common/temp_sensor.c
+++ b/common/temp_sensor.c
@@ -111,6 +111,7 @@ static int command_temps(int argc, char **argv)
switch (rv) {
case EC_SUCCESS:
ccprintf("%d K = %d C", t, K_TO_C(t));
+#ifdef CONFIG_THROTTLE_AP
if (thermal_params[i].temp_fan_off &&
thermal_params[i].temp_fan_max)
ccprintf(" %d%%",
@@ -118,6 +119,7 @@ static int command_temps(int argc, char **argv)
thermal_params[i].temp_fan_off,
thermal_params[i].temp_fan_max,
t));
+#endif
ccprintf("\n");
break;
case EC_ERROR_NOT_POWERED:
diff --git a/common/thermal.c b/common/thermal.c
index a2563f1785..d8a0ba52de 100644
--- a/common/thermal.c
+++ b/common/thermal.c
@@ -7,11 +7,9 @@
* implementation from the original version that shipped on Link.
*/
-#include "atomic.h"
#include "chipset.h"
#include "common.h"
#include "console.h"
-#include "dptf.h"
#include "fan.h"
#include "hooks.h"
#include "host_command.h"
@@ -26,93 +24,6 @@
#define CPRINTS(format, args...) cprints(CC_THERMAL, format, ## args)
/*****************************************************************************/
-/* DPTF temperature thresholds */
-
-static struct {
- int temp; /* degrees K, negative for disabled */
- cond_t over; /* watch for crossings */
-} dptf_threshold[TEMP_SENSOR_COUNT][DPTF_THRESHOLDS_PER_SENSOR];
-
-static void dptf_init(void)
-{
- int id, t;
-
- for (id = 0; id < TEMP_SENSOR_COUNT; id++)
- for (t = 0; t < DPTF_THRESHOLDS_PER_SENSOR; t++) {
- dptf_threshold[id][t].temp = -1;
- cond_init(&dptf_threshold[id][t].over, 0);
- }
-
-}
-DECLARE_HOOK(HOOK_INIT, dptf_init, HOOK_PRIO_DEFAULT);
-
-/* Keep track of which triggered sensor thresholds the AP has seen */
-static uint32_t dptf_seen;
-
-int dptf_query_next_sensor_event(void)
-{
- int id;
-
- for (id = 0; id < TEMP_SENSOR_COUNT; id++)
- if (dptf_seen & (1 << id)) { /* atomic? */
- atomic_clear(&dptf_seen, (1 << id));
- return id;
- }
-
- return -1;
-}
-
-/* Return true if any threshold transition occurs. */
-static int dpft_check_temp_threshold(int sensor_id, int temp)
-{
- int tripped = 0;
- int max, i;
-
- for (i = 0; i < DPTF_THRESHOLDS_PER_SENSOR; i++) {
-
- max = dptf_threshold[sensor_id][i].temp;
- if (max < 0) /* disabled? */
- continue;
-
- if (temp >= max)
- cond_set_true(&dptf_threshold[sensor_id][i].over);
- else if (temp <= max - DPTF_THRESHOLD_HYSTERESIS)
- cond_set_false(&dptf_threshold[sensor_id][i].over);
-
- if (cond_went_true(&dptf_threshold[sensor_id][i].over)) {
- CPRINTS("DPTF over threshold [%d][%d",
- sensor_id, i);
- atomic_or(&dptf_seen, (1 << sensor_id));
- tripped = 1;
- }
- if (cond_went_false(&dptf_threshold[sensor_id][i].over)) {
- CPRINTS("DPTF under threshold [%d][%d",
- sensor_id, i);
- atomic_or(&dptf_seen, (1 << sensor_id));
- tripped = 1;
- }
- }
-
- return tripped;
-}
-
-void dptf_set_temp_threshold(int sensor_id, int temp, int idx, int enable)
-{
- CPRINTS("DPTF sensor %d, threshold %d C, index %d, %sabled",
- sensor_id, K_TO_C(temp), idx, enable ? "en" : "dis");
-
- if (enable) {
- /* Don't update threshold condition if already enabled */
- if (dptf_threshold[sensor_id][idx].temp == -1)
- cond_init(&dptf_threshold[sensor_id][idx].over, 0);
- dptf_threshold[sensor_id][idx].temp = temp;
- atomic_clear(&dptf_seen, (1 << sensor_id));
- } else {
- dptf_threshold[sensor_id][idx].temp = -1;
- }
-}
-
-/*****************************************************************************/
/* EC-specific thermal controls */
test_mockable_static void smi_sensor_failure_warning(void)
@@ -146,7 +57,6 @@ static void thermal_control(void)
int num_valid_limits[EC_TEMP_THRESH_COUNT];
int num_sensors_read;
int fmax;
- int dptf_tripped;
int temp_fan_configured;
/* Get ready to count things */
@@ -155,7 +65,6 @@ static void thermal_control(void)
memset(num_valid_limits, 0, sizeof(num_valid_limits));
num_sensors_read = 0;
fmax = 0;
- dptf_tripped = 0;
temp_fan_configured = 0;
/* go through all the sensors */
@@ -191,9 +100,6 @@ static void thermal_control(void)
temp_fan_configured = 1;
}
-
- /* and check the dptf thresholds */
- dptf_tripped |= dpft_check_temp_threshold(i, t);
}
if (!num_sensors_read) {
@@ -266,10 +172,6 @@ static void thermal_control(void)
fan_set_percent_needed(i, fmax);
#endif
}
-
- /* Don't forget to signal any DPTF thresholds */
- if (dptf_tripped)
- host_set_single_event(EC_HOST_EVENT_THERMAL_THRESHOLD);
}
/* Wait until after the sensors have been read */
@@ -349,36 +251,6 @@ DECLARE_CONSOLE_COMMAND(thermalset, command_thermalset,
" Use -1 to skip.",
NULL);
-
-static int command_dptftemp(int argc, char **argv)
-{
- int id, t;
- int temp, trig;
-
- ccprintf("sensor thresh0 thresh1\n");
- for (id = 0; id < TEMP_SENSOR_COUNT; id++) {
- ccprintf(" %2d", id);
- for (t = 0; t < DPTF_THRESHOLDS_PER_SENSOR; t++) {
- temp = dptf_threshold[id][t].temp;
- trig = cond_is_true(&dptf_threshold[id][t].over);
- if (temp < 0)
- ccprintf(" --- ");
- else
- ccprintf(" %3d%c", temp,
- trig ? '*' : ' ');
- }
- ccprintf(" %s\n", temp_sensors[id].name);
- }
-
- ccprintf("AP seen mask: 0x%08x\n", dptf_seen);
- return EC_SUCCESS;
-}
-DECLARE_CONSOLE_COMMAND(dptftemp, command_dptftemp,
- NULL,
- "Print DPTF thermal parameters (degrees Kelvin)",
- NULL);
-
-
/*****************************************************************************/
/* Host commands. We'll reuse the host command number, but this is version 1,
* not version 0. Different structs, different meanings.
@@ -414,4 +286,3 @@ static int thermal_command_get_threshold(struct host_cmd_handler_args *args)
DECLARE_HOST_COMMAND(EC_CMD_THERMAL_GET_THRESHOLD,
thermal_command_get_threshold,
EC_VER_MASK(1));
-
diff --git a/include/config.h b/include/config.h
index d3b15932cf..0142e1286c 100644
--- a/include/config.h
+++ b/include/config.h
@@ -1768,6 +1768,13 @@
/* Compile common code for throttling the CPU based on the temp sensors */
#undef CONFIG_THROTTLE_AP
+/*
+ * If defined, dptf is enabled to manage thermals.
+ *
+ * NOTE: This doesn't mean that thermal control is completely taken care by
+ * DPTF. We have some hybrid solutions where the EC still manages the fans.
+ */
+#undef CONFIG_DPTF
/*****************************************************************************/
/* TPM-like configuration */
@@ -2246,6 +2253,16 @@
#endif
/******************************************************************************/
+/*
+ * DPTF must have temperature sensor enabled to get the readings for
+ * generating DPTF thresholds events.
+ */
+#if defined(CONFIG_DPTF) && !defined(CONFIG_TEMP_SENSOR)
+#define CONFIG_TEMP_SENSOR
+#endif
+
+
+/******************************************************************************/
/* The Matrix Keyboard Protocol depends on MKBP events. */
#ifdef CONFIG_KEYBOARD_PROTOCOL_MKBP
#define CONFIG_MKBP_EVENT
diff --git a/include/console_channel.inc b/include/console_channel.inc
index f6aefd7e6c..4faeff5281 100644
--- a/include/console_channel.inc
+++ b/include/console_channel.inc
@@ -60,6 +60,9 @@ CONSOLE_CHANNEL(CC_SWITCH, "switch")
#endif
CONSOLE_CHANNEL(CC_SYSTEM, "system")
CONSOLE_CHANNEL(CC_TASK, "task")
+#ifdef CONFIG_DPTF
+CONSOLE_CHANNEL(CC_DPTF, "dptf")
+#endif
CONSOLE_CHANNEL(CC_THERMAL, "thermal")
CONSOLE_CHANNEL(CC_TPM, "tpm")
CONSOLE_CHANNEL(CC_USB, "usb")