166 lines
3.7 KiB
C
166 lines
3.7 KiB
C
/* 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 */
|