diff --git a/drivers/espi/espi_mchp_xec.c b/drivers/espi/espi_mchp_xec.c index 14b2c43a7c2..c3d538f1897 100644 --- a/drivers/espi/espi_mchp_xec.c +++ b/drivers/espi/espi_mchp_xec.c @@ -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)); diff --git a/samples/drivers/espi/prj_mec1501modular_assy6885.conf b/samples/drivers/espi/prj_mec1501modular_assy6885.conf index cabf9b528e3..a4d3129ffaf 100644 --- a/samples/drivers/espi/prj_mec1501modular_assy6885.conf +++ b/samples/drivers/espi/prj_mec1501modular_assy6885.conf @@ -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 diff --git a/samples/drivers/espi/src/espi_oob_handler.c b/samples/drivers/espi/src/espi_oob_handler.c new file mode 100644 index 00000000000..80ba5773f0c --- /dev/null +++ b/samples/drivers/espi/src/espi_oob_handler.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#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 */ diff --git a/samples/drivers/espi/src/espi_oob_handler.h b/samples/drivers/espi/src/espi_oob_handler.h new file mode 100644 index 00000000000..ed09d5b803b --- /dev/null +++ b/samples/drivers/espi/src/espi_oob_handler.h @@ -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__ */ diff --git a/samples/drivers/espi/src/main.c b/samples/drivers/espi/src/main.c index 3f29d55b288..8907ff6503c 100644 --- a/samples/drivers/espi/src/main.c +++ b/samples/drivers/espi/src/main.c @@ -12,21 +12,11 @@ #include #include #include +#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));