blob: e0f03c95ddc7066e38a62246f4da81dae532900c [file] [log] [blame]
/* 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: %ph\n", HEX_BUF(r_buf, peci.r_len));
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 */