samples: drivers: espi: Showcase OOB Rx asynchronous handling
Add example to handle OOB host responses asynchronously. Signed-off-by: Jose Alberto Meza <jose.a.meza.arellano@intel.com>
This commit is contained in:
parent
9c6e81665b
commit
d38d913452
5 changed files with 296 additions and 80 deletions
|
@ -531,7 +531,6 @@ static int espi_xec_receive_oob(const struct device *dev,
|
|||
{
|
||||
uint8_t err_mask = MCHP_ESPI_OOB_RX_STS_IBERR |
|
||||
MCHP_ESPI_OOB_RX_STS_OVRUN;
|
||||
struct espi_xec_data *data = (struct espi_xec_data *)(dev->data);
|
||||
|
||||
if (ESPI_OOB_REGS->TX_STS & err_mask) {
|
||||
return -EIO;
|
||||
|
@ -539,7 +538,7 @@ static int espi_xec_receive_oob(const struct device *dev,
|
|||
|
||||
#ifndef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC
|
||||
int ret;
|
||||
struct espi_xec_data *data = (struct espi_xec_data *)(dev->driver_data);
|
||||
struct espi_xec_data *data = (struct espi_xec_data *)(dev->data);
|
||||
|
||||
/* Wait until ISR or timeout */
|
||||
ret = k_sem_take(&data->rx_lock, K_MSEC(MAX_OOB_TIMEOUT));
|
||||
|
|
|
@ -7,3 +7,5 @@ CONFIG_LOG_PROCESS_THREAD_SLEEP_MS=100
|
|||
CONFIG_ESPI_AUTOMATIC_WARNING_ACKNOWLEDGE=n
|
||||
# Sample code doesn't handle ACPI host communication
|
||||
CONFIG_ESPI_PERIPHERAL_HOST_IO=n
|
||||
# This only makes sense for system using this board
|
||||
CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC=y
|
||||
|
|
214
samples/drivers/espi/src/espi_oob_handler.c
Normal file
214
samples/drivers/espi/src/espi_oob_handler.c
Normal file
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <device.h>
|
||||
#include <soc.h>
|
||||
#include <drivers/gpio.h>
|
||||
#include <drivers/espi.h>
|
||||
#include <logging/log_ctrl.h>
|
||||
#include <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;
|
||||
#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);
|
||||
}
|
||||
|
||||
|
||||
bool need_temp;
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
context.cycles--;
|
||||
break;
|
||||
default:
|
||||
LOG_INF("Other host sender %x", sender);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (need_temp) {
|
||||
request_temp(context.espi_dev);
|
||||
need_temp = false;
|
||||
}
|
||||
}
|
||||
k_timer_stop(&temp_timer);
|
||||
}
|
||||
#endif /* CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC */
|
59
samples/drivers/espi/src/espi_oob_handler.h
Normal file
59
samples/drivers/espi/src/espi_oob_handler.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __ESPI_OOB_HANDLER_H__
|
||||
#define __ESPI_OOB_HANDLER_H__
|
||||
|
||||
/* eSPI host entity address */
|
||||
#define PCH_DEST_SLV_ADDR 0x02u
|
||||
#define SRC_SLV_ADDR 0x21u
|
||||
|
||||
#define OOB_RESPONSE_SENDER_INDEX 0x02u
|
||||
#define OOB_RESPONSE_DATA_INDEX 0x04u
|
||||
|
||||
|
||||
/* Temperature command opcode */
|
||||
#define OOB_CMDCODE 0x01u
|
||||
#define OOB_RESPONSE_LEN 0x05u
|
||||
|
||||
/* Maximum bytes for OOB transactions */
|
||||
#define MAX_ESPI_BUF_LEN 80u
|
||||
#define MIN_GET_TEMP_CYCLES 5u
|
||||
|
||||
/* 100ms */
|
||||
#define MAX_OOB_TIMEOUT 100ul
|
||||
|
||||
void oob_rx_handler(const struct device *dev, struct espi_callback *cb,
|
||||
struct espi_event event);
|
||||
|
||||
/**
|
||||
* @brief Retrieve PCH temperature over OOB channel.
|
||||
* Assumes OOB Tx and Rx as synchronous operation.
|
||||
*
|
||||
* @param dev eSPI driver handle.
|
||||
*
|
||||
* @retval 0 If successful.
|
||||
* @retval -ENOTSUP returned when OOB channel is not supported.
|
||||
* @retval -EINVAL is returned when OOB parameters are invalid.
|
||||
*
|
||||
*/
|
||||
int get_pch_temp_sync(const struct device *dev);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Retrieve PCH temperature over OOB channel.
|
||||
* Assumes OOB Tx and Rx as synchronous operation.
|
||||
*
|
||||
* @param dev eSPI driver handle.
|
||||
*
|
||||
* @retval 0 If successful.
|
||||
* @retval -ENOTSUP returned when OOB channel is not supported.
|
||||
* @retval -ETIMEOUT OOB operations could not be started.
|
||||
*
|
||||
*/
|
||||
int get_pch_temp_async(const struct device *dev);
|
||||
|
||||
#endif /* __ESPI_OOB_HANDLER_H__ */
|
|
@ -12,21 +12,11 @@
|
|||
#include <drivers/espi.h>
|
||||
#include <logging/log_ctrl.h>
|
||||
#include <logging/log.h>
|
||||
#ifdef CONFIG_ESPI_OOB_CHANNEL
|
||||
#include "espi_oob_handler.h"
|
||||
#endif
|
||||
LOG_MODULE_DECLARE(espi, CONFIG_ESPI_LOG_LEVEL);
|
||||
|
||||
/* eSPI host entity address */
|
||||
#define DEST_SLV_ADDR 0x02u
|
||||
#define SRC_SLV_ADDR 0x21u
|
||||
|
||||
/* Temperature command opcode */
|
||||
#define OOB_CMDCODE 0x01u
|
||||
#define OOB_RESPONSE_LEN 0x05u
|
||||
#define OOB_RESPONSE_INDEX 0x03u
|
||||
|
||||
/* Maximum bytes for OOB transactions */
|
||||
#define MAX_RESP_SIZE 20u
|
||||
#define MIN_GET_TEMP_CYCLES 5u
|
||||
|
||||
/* eSPI flash parameters */
|
||||
#define MAX_TEST_BUF_SIZE 1024u
|
||||
#define MAX_FLASH_REQUEST 64u
|
||||
|
@ -45,13 +35,6 @@ LOG_MODULE_DECLARE(espi, CONFIG_ESPI_LOG_LEVEL);
|
|||
#define EVENT_TYPE(x) (x & EVENT_MASK)
|
||||
#define EVENT_DETAILS(x) ((x & EVENT_DETAILS_MASK) >> EVENT_DETAILS_POS)
|
||||
|
||||
struct oob_header {
|
||||
uint8_t dest_slave_addr;
|
||||
uint8_t oob_cmd_code;
|
||||
uint8_t byte_cnt;
|
||||
uint8_t src_slave_addr;
|
||||
};
|
||||
|
||||
#define PWR_SEQ_TIMEOUT 3000u
|
||||
|
||||
/* The devicetree node identifier for the board power rails pins. */
|
||||
|
@ -74,8 +57,10 @@ static struct espi_callback espi_bus_cb;
|
|||
static struct espi_callback vw_rdy_cb;
|
||||
static struct espi_callback vw_cb;
|
||||
static struct espi_callback p80_cb;
|
||||
|
||||
static uint8_t espi_rst_sts;
|
||||
#ifdef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC
|
||||
static struct espi_callback oob_cb;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ESPI_FLASH_CHANNEL
|
||||
static uint8_t flash_write_buf[MAX_TEST_BUF_SIZE];
|
||||
|
@ -226,6 +211,10 @@ int espi_init(void)
|
|||
ESPI_BUS_EVENT_VWIRE_RECEIVED);
|
||||
espi_init_callback(&p80_cb, periph_handler,
|
||||
ESPI_BUS_PERIPHERAL_NOTIFICATION);
|
||||
#ifdef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC
|
||||
espi_init_callback(&oob_cb, oob_rx_handler,
|
||||
ESPI_BUS_EVENT_OOB_RECEIVED);
|
||||
#endif
|
||||
LOG_INF("complete");
|
||||
|
||||
LOG_INF("eSPI test - callbacks registration... ");
|
||||
|
@ -233,6 +222,9 @@ int espi_init(void)
|
|||
espi_add_callback(espi_dev, &vw_rdy_cb);
|
||||
espi_add_callback(espi_dev, &vw_cb);
|
||||
espi_add_callback(espi_dev, &p80_cb);
|
||||
#ifdef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC
|
||||
espi_add_callback(espi_dev, &oob_cb);
|
||||
#endif
|
||||
LOG_INF("complete");
|
||||
|
||||
return ret;
|
||||
|
@ -479,53 +471,6 @@ static int espi_flash_test(uint32_t start_flash_addr, uint8_t blocks)
|
|||
}
|
||||
#endif /* CONFIG_ESPI_FLASH_CHANNEL */
|
||||
|
||||
int get_pch_temp(const struct device *dev, int *temp)
|
||||
{
|
||||
struct espi_oob_packet req_pckt;
|
||||
struct espi_oob_packet resp_pckt;
|
||||
struct oob_header oob_hdr;
|
||||
uint8_t buf[MAX_RESP_SIZE];
|
||||
int ret;
|
||||
|
||||
LOG_INF("%s", __func__);
|
||||
|
||||
oob_hdr.dest_slave_addr = 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);
|
||||
resp_pckt.buf = (uint8_t *)&buf;
|
||||
resp_pckt.len = MAX_RESP_SIZE;
|
||||
|
||||
ret = espi_send_oob(dev, &req_pckt);
|
||||
if (ret) {
|
||||
LOG_ERR("OOB Tx failed %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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 (resp_pckt.len == OOB_RESPONSE_LEN) {
|
||||
*temp = buf[OOB_RESPONSE_INDEX];
|
||||
} else {
|
||||
LOG_ERR("Incorrect size response");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_ESPI_AUTOMATIC_BOOT_DONE_ACKNOWLEDGE
|
||||
static void send_slave_bootdone(void)
|
||||
{
|
||||
|
@ -674,16 +619,13 @@ int espi_test(void)
|
|||
/* Attempt to use OOB channel to read temperature, regardless of
|
||||
* if is enabled or not.
|
||||
*/
|
||||
for (int i = 0; i < MIN_GET_TEMP_CYCLES; i++) {
|
||||
int temp;
|
||||
|
||||
ret = get_pch_temp(espi_dev, &temp);
|
||||
if (ret) {
|
||||
LOG_ERR("eSPI OOB transaction failed %d", ret);
|
||||
} else {
|
||||
LOG_INF("Temp: %d ", temp);
|
||||
}
|
||||
}
|
||||
#ifndef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC
|
||||
/* System without host-initiated OOB Rx traffic */
|
||||
get_pch_temp_sync(espi_dev);
|
||||
#else
|
||||
/* System with host-initiated OOB Rx traffic */
|
||||
get_pch_temp_async(espi_dev);
|
||||
#endif
|
||||
|
||||
/* Cleanup */
|
||||
k_sleep(K_SECONDS(1));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue