blob: 59f988c7ad5197ee9693de3df18d3e4479f8be2a [file] [log] [blame]
/*
* Copyright (c) 2020 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/device.h>
#include <soc.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/espi.h>
#include <zephyr/logging/log_ctrl.h>
#include <zephyr/logging/log.h>
#include "espi_oob_handler.h"
LOG_MODULE_DECLARE(espi, CONFIG_ESPI_LOG_LEVEL);
struct oob_header {
uint8_t dest_slave_addr;
uint8_t oob_cmd_code;
uint8_t byte_cnt;
uint8_t src_slave_addr;
};
#ifdef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC
#define OOB_THREAD_STACK_SIZE 512ul
#define OOB_THREAD_PRIORITY K_PRIO_COOP(5)
#define OOB_THREAD_WAIT -1
/* Thread to process asynchronous callbacks */
void espihub_thread(void *p1, void *p2, void *p3);
void temperature_timer(struct k_timer *timer_id);
K_TIMER_DEFINE(temp_timer, temperature_timer, NULL);
K_THREAD_DEFINE(espihub_thrd_id, OOB_THREAD_STACK_SIZE, espihub_thread,
NULL, NULL, NULL,
OOB_THREAD_PRIORITY, K_INHERIT_PERMS, OOB_THREAD_WAIT);
K_MSGQ_DEFINE(from_host, sizeof(uint8_t), 8, 4);
struct thread_context {
const struct device *espi_dev;
int cycles;
};
static struct thread_context context;
static bool need_temp;
#endif
static struct espi_oob_packet resp_pckt;
static uint8_t buf[MAX_ESPI_BUF_LEN];
static int request_temp(const struct device *dev)
{
int ret;
struct oob_header oob_hdr;
struct espi_oob_packet req_pckt;
LOG_WRN("%s", __func__);
oob_hdr.dest_slave_addr = PCH_DEST_SLV_ADDR;
oob_hdr.oob_cmd_code = OOB_CMDCODE;
oob_hdr.byte_cnt = 1;
oob_hdr.src_slave_addr = SRC_SLV_ADDR;
/* Packetize OOB request */
req_pckt.buf = (uint8_t *)&oob_hdr;
req_pckt.len = sizeof(struct oob_header);
ret = espi_send_oob(dev, &req_pckt);
if (ret) {
LOG_ERR("OOB Tx failed %d", ret);
return ret;
}
return 0;
}
static int retrieve_packet(const struct device *dev, uint8_t *sender)
{
int ret;
#ifdef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC
/* Note that no data is in the item */
uint8_t response_len;
if (k_msgq_num_used_get(&from_host) == 0U) {
return -EINVAL;
}
k_msgq_get(&from_host, &response_len, K_FOREVER);
#endif
resp_pckt.buf = (uint8_t *)&buf;
resp_pckt.len = MAX_ESPI_BUF_LEN;
ret = espi_receive_oob(dev, &resp_pckt);
if (ret) {
LOG_ERR("OOB Rx failed %d", ret);
return ret;
}
LOG_INF("OOB transaction completed rcvd: %d bytes", resp_pckt.len);
for (int i = 0; i < resp_pckt.len; i++) {
LOG_INF("%x ", buf[i]);
}
if (sender) {
*sender = buf[OOB_RESPONSE_SENDER_INDEX];
}
return 0;
}
int get_pch_temp_sync(const struct device *dev)
{
int ret;
for (int i = 0; i < MIN_GET_TEMP_CYCLES; i++) {
ret = request_temp(dev);
if (ret) {
LOG_ERR("OOB req failed %d", ret);
return ret;
}
ret = retrieve_packet(dev, NULL);
if (ret) {
LOG_ERR("OOB retrieve failed %d", ret);
return ret;
}
}
return 0;
}
int get_pch_temp_async(const struct device *dev)
{
#if !defined(CONFIG_ESPI_OOB_CHANNEL) || \
!defined(CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC)
return -ENOTSUP;
#else
context.espi_dev = dev;
context.cycles = MIN_GET_TEMP_CYCLES;
k_thread_start(espihub_thrd_id);
k_thread_join(espihub_thrd_id, K_FOREVER);
return 0;
#endif
}
#ifdef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC
void oob_rx_handler(const struct device *dev, struct espi_callback *cb,
struct espi_event event)
{
uint8_t last_resp_len = event.evt_details;
LOG_WRN("%s", __func__);
/* Post for post-processing in a thread
* Should not attempt to retrieve in callback context
*/
k_msgq_put(&from_host, &last_resp_len, K_NO_WAIT);
}
void temperature_timer(struct k_timer *timer_id)
{
LOG_WRN("%s", __func__);
need_temp = true;
}
void espihub_thread(void *p1, void *p2, void *p3)
{
int ret;
uint8_t temp;
uint8_t sender;
LOG_DBG("%s", __func__);
k_timer_start(&temp_timer, K_MSEC(100), K_MSEC(100));
while (context.cycles > 0) {
k_msleep(50);
ret = retrieve_packet(context.espi_dev, &sender);
if (!ret) {
switch (sender) {
case PCH_DEST_SLV_ADDR:
LOG_INF("PCH response");
/* Any other checks */
if (resp_pckt.len == OOB_RESPONSE_LEN) {
temp = buf[OOB_RESPONSE_DATA_INDEX];
LOG_INF("Temp %d", temp);
} else {
LOG_ERR("Incorrect size response");
}
break;
default:
LOG_INF("Other host sender %x", sender);
}
} else {
LOG_ERR("Failure to retrieve temp %d", ret);
}
/* Decrease cycles in both cases failure/success */
context.cycles--;
if (need_temp) {
request_temp(context.espi_dev);
need_temp = false;
}
}
k_timer_stop(&temp_timer);
}
#endif /* CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC */