summaryrefslogtreecommitdiff
path: root/common/peci.c
diff options
context:
space:
mode:
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 */