|  | /* | 
|  | * Copyright (c) 2020 Intel Corporation | 
|  | * | 
|  | * SPDX-License-Identifier: Apache-2.0 | 
|  | */ | 
|  |  | 
|  | #include <zephyr.h> | 
|  | #include <sys/printk.h> | 
|  | #include <drivers/peci.h> | 
|  | #include <soc.h> | 
|  |  | 
|  | #define TASK_STACK_SIZE         1024 | 
|  | #define PRIORITY                7 | 
|  |  | 
|  | /* PECI Host address */ | 
|  | #define PECI_HOST_ADDR          0x30u | 
|  | /* PECI Host bitrate 1Mbps */ | 
|  | #define PECI_HOST_BITRATE       1000u | 
|  |  | 
|  | #define PECI_CONFIGINDEX_TJMAX  16u | 
|  | #define PECI_CONFIGHOSTID       0u | 
|  | #define PECI_CONFIGPARAM        0u | 
|  |  | 
|  | #define PECI_SAFE_TEMP          72 | 
|  |  | 
|  | static const struct device *peci_dev; | 
|  | static bool peci_initialized; | 
|  | static uint8_t tjmax; | 
|  | static uint8_t rx_fcs; | 
|  | static void monitor_temperature_func(void *dummy1, void *dummy2, void *dummy3); | 
|  |  | 
|  | static struct k_thread temp_id; | 
|  | K_THREAD_STACK_DEFINE(temp_stack, TASK_STACK_SIZE); | 
|  |  | 
|  | int peci_ping(void) | 
|  | { | 
|  | int ret; | 
|  | struct peci_msg packet; | 
|  |  | 
|  | printk("%s\n", __func__); | 
|  |  | 
|  | packet.addr = PECI_HOST_ADDR; | 
|  | packet.cmd_code = PECI_CMD_PING; | 
|  | packet.tx_buffer.buf = NULL; | 
|  | packet.tx_buffer.len = PECI_PING_WR_LEN; | 
|  | packet.rx_buffer.buf = NULL; | 
|  | packet.rx_buffer.len = PECI_PING_RD_LEN; | 
|  |  | 
|  | ret = peci_transfer(peci_dev, &packet); | 
|  | if (ret) { | 
|  | printk("ping failed %d\n", ret); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int peci_get_tjmax(uint8_t *tjmax) | 
|  | { | 
|  | int ret; | 
|  | int retries = 3; | 
|  | uint8_t peci_resp; | 
|  | struct peci_msg packet; | 
|  |  | 
|  | uint8_t peci_resp_buf[PECI_RD_PKG_LEN_DWORD+1]; | 
|  | uint8_t peci_req_buf[] = { PECI_CONFIGHOSTID, | 
|  | PECI_CONFIGINDEX_TJMAX, | 
|  | PECI_CONFIGPARAM & 0x00FF, | 
|  | (PECI_CONFIGPARAM & 0xFF00) >> 8, | 
|  | }; | 
|  |  | 
|  | packet.tx_buffer.buf = peci_req_buf; | 
|  | packet.tx_buffer.len = PECI_RD_PKG_WR_LEN; | 
|  | packet.rx_buffer.buf = peci_resp_buf; | 
|  | packet.rx_buffer.len = PECI_RD_PKG_LEN_DWORD; | 
|  |  | 
|  | do { | 
|  | rx_fcs = 0; | 
|  | packet.addr = PECI_HOST_ADDR; | 
|  | packet.cmd_code = PECI_CMD_RD_PKG_CFG0; | 
|  |  | 
|  | ret = peci_transfer(peci_dev, &packet); | 
|  |  | 
|  | for (int i = 0; i < PECI_RD_PKG_LEN_DWORD; i++) { | 
|  | printk("%02x\n", packet.rx_buffer.buf[i]); | 
|  | } | 
|  |  | 
|  | peci_resp = packet.rx_buffer.buf[0]; | 
|  | rx_fcs = packet.rx_buffer.buf[PECI_RD_PKG_LEN_DWORD]; | 
|  | k_sleep(K_MSEC(1)); | 
|  | printk("\npeci_resp %x\n", peci_resp); | 
|  | retries--; | 
|  | } while ((peci_resp != PECI_CC_RSP_SUCCESS) && (retries > 0)); | 
|  |  | 
|  | *tjmax = packet.rx_buffer.buf[3]; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int peci_get_temp(int *temperature) | 
|  | { | 
|  | int16_t raw_cpu_temp; | 
|  | int ret; | 
|  | struct peci_msg packet = {0}; | 
|  |  | 
|  | uint8_t peci_resp_buf[PECI_GET_TEMP_RD_LEN+1]; | 
|  |  | 
|  | rx_fcs = 0; | 
|  | packet.tx_buffer.buf = NULL; | 
|  | packet.tx_buffer.len = PECI_GET_TEMP_WR_LEN; | 
|  | packet.rx_buffer.buf = peci_resp_buf; | 
|  | packet.rx_buffer.len = PECI_GET_TEMP_RD_LEN; | 
|  |  | 
|  | packet.addr = PECI_HOST_ADDR; | 
|  | packet.cmd_code = PECI_CMD_GET_TEMP0; | 
|  |  | 
|  | ret = peci_transfer(peci_dev, &packet); | 
|  | if (ret) { | 
|  | printk("Get temp failed %d\n", ret); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | rx_fcs = packet.rx_buffer.buf[PECI_GET_TEMP_RD_LEN]; | 
|  | printk("R FCS %x\n", rx_fcs); | 
|  | printk("Temp bytes: %02x", packet.rx_buffer.buf[0]); | 
|  | printk("%02x\n", packet.rx_buffer.buf[1]); | 
|  |  | 
|  | raw_cpu_temp = (int16_t)(packet.rx_buffer.buf[0] | | 
|  | (int16_t)((packet.rx_buffer.buf[1] << 8) & 0xFF00)); | 
|  |  | 
|  | if (raw_cpu_temp == 0x8000) { | 
|  | printk("Invalid temp %x\n", raw_cpu_temp); | 
|  | *temperature = PECI_SAFE_TEMP; | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | raw_cpu_temp = (raw_cpu_temp >> 6) | 0x7E00; | 
|  | *temperature = raw_cpu_temp + tjmax; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | void read_temp(void) | 
|  | { | 
|  | int ret; | 
|  | int temp; | 
|  |  | 
|  | ret = peci_get_temp(&temp); | 
|  |  | 
|  | if (!ret) { | 
|  | printk("Temperature %d C\n", temp); | 
|  | } | 
|  | } | 
|  |  | 
|  | void get_max_temp(void) | 
|  | { | 
|  | int ret; | 
|  |  | 
|  | ret = peci_get_tjmax(&tjmax); | 
|  | if (ret) { | 
|  | printk("Fail to obtain maximum temperature: %d\n", ret); | 
|  | } else { | 
|  | printk("Maximum temperature: %u\n", tjmax); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void monitor_temperature_func(void *dummy1, void *dummy2, void *dummy3) | 
|  | { | 
|  | while (true) { | 
|  | k_sleep(K_MSEC(1000)); | 
|  | if (peci_initialized) { | 
|  | read_temp(); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void main(void) | 
|  | { | 
|  | #if DT_NODE_HAS_STATUS(DT_ALIAS(peci_0), okay) | 
|  | int ret; | 
|  | #endif | 
|  |  | 
|  | printk("PECI sample test\n"); | 
|  |  | 
|  | k_thread_create(&temp_id, temp_stack, TASK_STACK_SIZE, | 
|  | monitor_temperature_func, NULL, NULL, NULL, PRIORITY, | 
|  | K_INHERIT_PERMS, K_FOREVER); | 
|  |  | 
|  | #if DT_NODE_HAS_STATUS(DT_ALIAS(peci_0), okay) | 
|  | peci_dev = DEVICE_DT_GET(DT_ALIAS(peci_0)); | 
|  | if (!device_is_ready(peci_dev)) { | 
|  | printk("Err: PECI device is not ready\n"); | 
|  | return; | 
|  | } | 
|  |  | 
|  | ret = peci_config(peci_dev, 1000u); | 
|  | if (ret) { | 
|  | printk("Err: Fail to configure bitrate\n"); | 
|  | return; | 
|  | } | 
|  |  | 
|  | peci_enable(peci_dev); | 
|  |  | 
|  | tjmax = 100; | 
|  |  | 
|  | get_max_temp(); | 
|  | printk("Start thread...\n"); | 
|  | k_thread_start(&temp_id); | 
|  |  | 
|  | peci_initialized = true; | 
|  | #endif | 
|  | } |