summaryrefslogtreecommitdiff
path: root/common/peci.c
diff options
context:
space:
mode:
authorVijay Hiremath <vijay.p.hiremath@intel.com>2019-03-08 17:29:45 -0800
committerchrome-bot <chrome-bot@chromium.org>2019-05-28 10:44:36 -0700
commit148145c4457e70b0da517b4b9f961338fc21bd46 (patch)
tree08c8a5d7d2ccee44919d3d586f961d5cf4cfe41e /common/peci.c
parent68763771658af368ceaa07803e8dfb5b841c9cf6 (diff)
downloadchrome-ec-148145c4457e70b0da517b4b9f961338fc21bd46.tar.gz
PECI: Move non-chipset specific PECI code to common folder
The Platform Environment Control Interface (PECI) is a thermal management standard with one-wire bus interface that provides a communication channel between Intel processor and chipset components to external monitoring or control devices. As we can read the CPU temperature over PECI more accurately than the thermistors, we can eliminate usage of thermistors for reading CPU temperature. BUG=b:128666114 BRANCH=none TEST=Manually tested on Dragonegg, able read CPU temperature. Change-Id: Ie0845ca776e6a7e14511dc9315d6d83cdd5f09a6 Signed-off-by: Vijay Hiremath <vijay.p.hiremath@intel.com> Reviewed-on: https://chromium-review.googlesource.com/1622740 Commit-Ready: Vijay P Hiremath <vijay.p.hiremath@intel.com> Tested-by: Vijay P Hiremath <vijay.p.hiremath@intel.com> Legacy-Commit-Queue: Commit Bot <commit-bot@chromium.org> Reviewed-by: Jett Rink <jettrink@chromium.org>
Diffstat (limited to 'common/peci.c')
-rw-r--r--common/peci.c165
1 files changed, 165 insertions, 0 deletions
diff --git a/common/peci.c b/common/peci.c
new file mode 100644
index 0000000000..b4422de05e
--- /dev/null
+++ b/common/peci.c
@@ -0,0 +1,165 @@
+/* Copyright 2019 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.
+ */
+
+/* PECI interface for Chrome EC */
+
+#include "chipset.h"
+#include "console.h"
+#include "peci.h"
+#include "util.h"
+
+static int peci_get_cpu_temp(int *cpu_temp)
+{
+ int rv;
+ uint8_t r_buf[PECI_GET_TEMP_READ_LENGTH] = {0};
+ struct peci_data peci = {
+ .cmd_code = PECI_CMD_GET_TEMP,
+ .addr = PECI_TARGET_ADDRESS,
+ .w_len = PECI_GET_TEMP_WRITE_LENGTH,
+ .r_len = PECI_GET_TEMP_READ_LENGTH,
+ .w_buf = NULL,
+ .r_buf = r_buf,
+ .timeout_us = PECI_GET_TEMP_TIMEOUT_US,
+ };
+
+ rv = peci_transaction(&peci);
+ if (rv)
+ return rv;
+
+ /* Get relative raw data of temperature. */
+ *cpu_temp = (r_buf[1] << 8) | r_buf[0];
+
+ /* Convert relative raw data to degrees C. */
+ *cpu_temp = ((*cpu_temp ^ 0xFFFF) + 1) >> 6;
+
+ /*
+ * When the AP transitions into S0, it is possible, depending on the
+ * timing of the PECI sample, to read an invalid temperature. This is
+ * very rare, but when it does happen the temperature returned is
+ * greater than or equal to CONFIG_PECI_TJMAX.
+ */
+ if (*cpu_temp >= CONFIG_PECI_TJMAX)
+ return EC_ERROR_UNKNOWN;
+
+ /* temperature in K */
+ *cpu_temp = CONFIG_PECI_TJMAX - *cpu_temp + 273;
+
+ return EC_SUCCESS;
+}
+
+int peci_temp_sensor_get_val(int idx, int *temp_ptr)
+{
+ int i, rv;
+
+ if (!chipset_in_state(CHIPSET_STATE_ON | CHIPSET_STATE_STANDBY))
+ return EC_ERROR_NOT_POWERED;
+
+ /*
+ * Retry reading PECI CPU temperature if the first sample is
+ * invalid or failed to obtain.
+ */
+ for (i = 0; i < 2; i++) {
+ rv = peci_get_cpu_temp(temp_ptr);
+ if (!rv)
+ break;
+ }
+
+ return rv;
+}
+
+/*****************************************************************************/
+/* Console commands */
+#ifdef CONFIG_CMD_PECI
+static int peci_cmd(int argc, char **argv)
+{
+ uint8_t r_buf[PECI_READ_DATA_FIFO_SIZE] = {0};
+ uint8_t w_buf[PECI_WRITE_DATA_FIFO_SIZE] = {0};
+ struct peci_data peci = {
+ .w_buf = w_buf,
+ .r_buf = r_buf,
+ };
+
+ int param;
+ char *e;
+
+ if ((argc < 6) || (argc > 8))
+ return EC_ERROR_PARAM_COUNT;
+
+ peci.addr = strtoi(argv[1], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM1;
+
+ peci.w_len = strtoi(argv[2], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM2;
+
+ peci.r_len = strtoi(argv[3], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM3;
+
+ peci.cmd_code = strtoi(argv[4], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM4;
+
+ peci.timeout_us = strtoi(argv[5], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM5;
+
+ if (argc > 6) {
+ param = strtoi(argv[6], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM6;
+
+ /* MSB of parameter */
+ w_buf[3] = (uint8_t)(param >> 24);
+ /* LSB of parameter */
+ w_buf[2] = (uint8_t)(param >> 16);
+ /* Index */
+ w_buf[1] = (uint8_t)(param >> 8);
+ /* Host ID[7:1] & Retry[0] */
+ w_buf[0] = (uint8_t)(param >> 0);
+
+ if (argc > 7) {
+ param = strtoi(argv[7], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM7;
+
+ /* Data (1, 2 or 4 bytes) */
+ w_buf[7] = (uint8_t)(param >> 24);
+ w_buf[6] = (uint8_t)(param >> 16);
+ w_buf[5] = (uint8_t)(param >> 8);
+ w_buf[4] = (uint8_t)(param >> 0);
+ }
+ } else {
+ peci.w_len = 0x00;
+ }
+
+ if (peci_transaction(&peci)) {
+ ccprintf("PECI transaction error\n");
+ return EC_ERROR_UNKNOWN;
+ }
+ ccprintf("PECI read data: %.*h\n", peci.r_len, r_buf);
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(peci, peci_cmd,
+ "addr wlen rlen cmd timeout(us)",
+ "PECI command");
+
+static int command_peci_temp(int argc, char **argv)
+{
+ int t;
+
+ if (peci_get_cpu_temp(&t) != EC_SUCCESS) {
+ ccprintf("PECI get cpu temp error\n");
+ return EC_ERROR_UNKNOWN;
+ }
+
+ ccprintf("CPU temp: %d K, %d C\n", t, K_TO_C(t));
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(pecitemp, command_peci_temp,
+ NULL,
+ "Print CPU temperature");
+#endif /* CONFIG_CMD_PECI */