ec_host_cmd: add eSPI peripheral for the host commands

This commit adds the support for host commands being transported
by the eSPI subsystem.

Signed-off-by: Michał Barnaś <mb@semihalf.com>
This commit is contained in:
Michał Barnaś 2022-05-23 18:49:42 +02:00 committed by Carles Cufí
commit 94458f88b9
9 changed files with 157 additions and 5 deletions

View file

@ -5,3 +5,7 @@ zephyr_library()
zephyr_library_sources_ifdef( zephyr_library_sources_ifdef(
CONFIG_EC_HOST_CMD_SIMULATOR CONFIG_EC_HOST_CMD_SIMULATOR
ec_host_cmd_simulator.c) ec_host_cmd_simulator.c)
zephyr_library_sources_ifdef(
CONFIG_EC_HOST_CMD_PERIPH_ESPI
ec_host_cmd_periph_espi.c)

View file

@ -5,6 +5,7 @@
menuconfig EC_HOST_CMD_PERIPH menuconfig EC_HOST_CMD_PERIPH
bool "Embedded Controller Host Command peripheral support" bool "Embedded Controller Host Command peripheral support"
depends on EC_HOST_CMD
help help
Enable the embedded controller host command peripheral driver. This Enable the embedded controller host command peripheral driver. This
is needed by the EC host command framework to send and receive data is needed by the EC host command framework to send and receive data
@ -12,11 +13,24 @@ menuconfig EC_HOST_CMD_PERIPH
if EC_HOST_CMD_PERIPH if EC_HOST_CMD_PERIPH
choice
prompt "Host commands peripheral"
config EC_HOST_CMD_SIMULATOR config EC_HOST_CMD_SIMULATOR
bool "Embedded Controller Host Command Peripheral Simulator" bool "Embedded Controller Host Command Peripheral Simulator"
default y
depends on DT_HAS_ZEPHYR_SIM_EC_HOST_CMD_PERIPH_ENABLED depends on DT_HAS_ZEPHYR_SIM_EC_HOST_CMD_PERIPH_ENABLED
help help
Enable the EC host command simulator. Enable the EC host command simulator.
config EC_HOST_CMD_PERIPH_ESPI
bool "Host commands support using eSPI bus"
depends on ESPI_PERIPHERAL_EC_HOST_CMD
depends on ESPI_PERIPHERAL_CUSTOM_OPCODE
depends on DT_HAS_ZEPHYR_EC_HOST_CMD_PERIPH_ESPI_ENABLED
help
Enable support for Embedded Controller host commands using
the eSPI bus.
endchoice
endif # EC_HOST_CMD_PERIPH endif # EC_HOST_CMD_PERIPH

View file

@ -0,0 +1,106 @@
/*
* Copyright (c) 2022 Google LLC
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT zephyr_ec_host_cmd_periph_espi
#include <string.h>
#include <zephyr/device.h>
#include <zephyr/drivers/ec_host_cmd_periph/ec_host_cmd_periph.h>
#include <zephyr/drivers/espi.h>
#include <zephyr/mgmt/ec_host_cmd.h>
BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, "Invalid number of eSPI peripherals");
#define ESPI_BUS DT_PHANDLE(DT_DRV_INST(0), bus)
#define ESPI_DEVICE DEVICE_DT_GET(ESPI_BUS)
struct ec_host_cmd_periph_espi_data {
struct k_sem handler_owns;
struct k_sem dev_owns;
uint32_t rx_buffer_len;
struct espi_callback espi_cb;
uint8_t *espi_shm;
};
static void ec_host_cmd_periph_espi_handler(const struct device *dev, struct espi_callback *cb,
struct espi_event espi_evt)
{
struct ec_host_cmd_periph_espi_data *data =
CONTAINER_OF(cb, struct ec_host_cmd_periph_espi_data, espi_cb);
uint16_t event_type = (uint16_t)espi_evt.evt_details;
if (event_type != ESPI_PERIPHERAL_EC_HOST_CMD) {
return;
}
if (k_sem_take(&data->dev_owns, K_NO_WAIT) != 0) {
int res = EC_HOST_CMD_IN_PROGRESS;
espi_write_lpc_request(ESPI_DEVICE, ECUSTOM_HOST_CMD_SEND_RESULT, &res);
return;
}
k_sem_give(&data->handler_owns);
}
int ec_host_cmd_periph_espi_init(const struct device *dev, struct ec_host_cmd_periph_rx_ctx *rx_ctx)
{
struct ec_host_cmd_periph_espi_data *data = dev->data;
if (rx_ctx == NULL) {
return -EINVAL;
}
rx_ctx->buf = data->espi_shm;
rx_ctx->len = &data->rx_buffer_len;
rx_ctx->dev_owns = &data->dev_owns;
rx_ctx->handler_owns = &data->handler_owns;
return 0;
}
int ec_host_cmd_periph_espi_send(const struct device *dev,
const struct ec_host_cmd_periph_tx_buf *buf)
{
struct ec_host_cmd_periph_espi_data *data = dev->data;
struct ec_host_cmd_response_header *resp_hdr = buf->buf;
uint32_t result = resp_hdr->result;
memcpy(data->espi_shm, buf->buf, buf->len);
return espi_write_lpc_request(ESPI_DEVICE, ECUSTOM_HOST_CMD_SEND_RESULT, &result);
}
static const struct ec_host_cmd_periph_api ec_host_cmd_api = {
.init = &ec_host_cmd_periph_espi_init,
.send = &ec_host_cmd_periph_espi_send,
};
static int ec_host_cmd_espi_init(const struct device *dev)
{
struct ec_host_cmd_periph_espi_data *data = dev->data;
/* Allow writing to rx buff at startup and block on reading. */
k_sem_init(&data->handler_owns, 0, 1);
k_sem_init(&data->dev_owns, 1, 1);
espi_init_callback(&data->espi_cb, ec_host_cmd_periph_espi_handler,
ESPI_BUS_PERIPHERAL_NOTIFICATION);
espi_add_callback(ESPI_DEVICE, &data->espi_cb);
espi_read_lpc_request(ESPI_DEVICE, ECUSTOM_HOST_CMD_GET_PARAM_MEMORY,
(uint32_t *)&data->espi_shm);
espi_read_lpc_request(ESPI_DEVICE, ECUSTOM_HOST_CMD_GET_PARAM_MEMORY_SIZE,
&data->rx_buffer_len);
return 0;
}
/* Assume only one peripheral */
static struct ec_host_cmd_periph_espi_data espi_data;
DEVICE_DT_INST_DEFINE(0, ec_host_cmd_espi_init, NULL, &espi_data, NULL, POST_KERNEL,
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &ec_host_cmd_api);

View file

@ -805,6 +805,9 @@ static int espi_it8xxx2_read_lpc_request(const struct device *dev,
*data = (uint32_t)&h2ram_pool[ *data = (uint32_t)&h2ram_pool[
CONFIG_ESPI_PERIPHERAL_HOST_CMD_PARAM_PORT_NUM]; CONFIG_ESPI_PERIPHERAL_HOST_CMD_PARAM_PORT_NUM];
break; break;
case ECUSTOM_HOST_CMD_GET_PARAM_MEMORY_SIZE:
*data = CONFIG_ESPI_IT8XXX2_HC_H2RAM_SIZE;
break;
default: default:
return -EINVAL; return -EINVAL;
} }

View file

@ -720,6 +720,9 @@ static int ecust_rd_req(const struct device *dev,
case ECUSTOM_HOST_CMD_GET_PARAM_MEMORY: case ECUSTOM_HOST_CMD_GET_PARAM_MEMORY:
*data = (uint32_t)ec_host_cmd_sram; *data = (uint32_t)ec_host_cmd_sram;
break; break;
case ECUSTOM_HOST_CMD_GET_PARAM_MEMORY_SIZE:
*data = CONFIG_ESPI_XEC_PERIPHERAL_HOST_CMD_PARAM_SIZE;
break;
#endif #endif
default: default:
return -EINVAL; return -EINVAL;

View file

@ -830,6 +830,9 @@ int npcx_host_periph_read_request(enum lpc_peripheral_opcode op,
case ECUSTOM_HOST_CMD_GET_PARAM_MEMORY: case ECUSTOM_HOST_CMD_GET_PARAM_MEMORY:
*data = (uint32_t)shm_host_cmd; *data = (uint32_t)shm_host_cmd;
break; break;
case ECUSTOM_HOST_CMD_GET_PARAM_MEMORY_SIZE:
*data = CONFIG_ESPI_NPCX_PERIPHERAL_HOST_CMD_PARAM_SIZE;
break;
default: default:
return -EINVAL; return -EINVAL;
} }

View file

@ -0,0 +1,15 @@
# SPDX-License-Identifier: Apache-2.0
description: Host Command Peripheral using the eSPI bus
compatible: "zephyr,ec-host-cmd-periph-espi"
include: base.yaml
properties:
bus:
required: true
type: phandle
description:
Phandle to the eSPI bus which will be used for communication with AP
by the host commands subsystem

View file

@ -285,6 +285,7 @@ enum lpc_peripheral_opcode {
/* Other customized transactions */ /* Other customized transactions */
ECUSTOM_HOST_SUBS_INTERRUPT_EN = ECUSTOM_START_OPCODE, ECUSTOM_HOST_SUBS_INTERRUPT_EN = ECUSTOM_START_OPCODE,
ECUSTOM_HOST_CMD_GET_PARAM_MEMORY, ECUSTOM_HOST_CMD_GET_PARAM_MEMORY,
ECUSTOM_HOST_CMD_GET_PARAM_MEMORY_SIZE,
ECUSTOM_HOST_CMD_SEND_RESULT, ECUSTOM_HOST_CMD_SEND_RESULT,
#endif /* CONFIG_ESPI_PERIPHERAL_CUSTOM_OPCODE */ #endif /* CONFIG_ESPI_PERIPHERAL_CUSTOM_OPCODE */
}; };

View file

@ -10,9 +10,8 @@
#include <zephyr/kernel.h> #include <zephyr/kernel.h>
#include <string.h> #include <string.h>
#if !DT_HAS_CHOSEN(zephyr_ec_host_interface) BUILD_ASSERT(DT_HAS_CHOSEN(zephyr_ec_host_interface),
#error Must chose zephyr,ec-host-interface in device tree "Must choose zephyr,ec-host-interface in device tree");
#endif
#define DT_HOST_CMD_DEV DT_CHOSEN(zephyr_ec_host_interface) #define DT_HOST_CMD_DEV DT_CHOSEN(zephyr_ec_host_interface)
@ -82,9 +81,10 @@ static void handle_host_cmds_entry(void *arg1, void *arg2, void *arg3)
*/ */
send_error_response(ec_host_cmd_dev, send_error_response(ec_host_cmd_dev,
EC_HOST_CMD_ERROR); EC_HOST_CMD_ERROR);
continue;
} }
/* rx buf and len now have valid incoming data */
/* rx buf and len now have valid incoming data */
if (*rx.len < RX_HEADER_SIZE) { if (*rx.len < RX_HEADER_SIZE) {
send_error_response(ec_host_cmd_dev, send_error_response(ec_host_cmd_dev,
EC_HOST_CMD_REQUEST_TRUNCATED); EC_HOST_CMD_REQUEST_TRUNCATED);
@ -182,6 +182,7 @@ static void handle_host_cmds_entry(void *arg1, void *arg2, void *arg3)
tx_header->prtcl_ver = 3; tx_header->prtcl_ver = 3;
tx_header->result = EC_HOST_CMD_SUCCESS; tx_header->result = EC_HOST_CMD_SUCCESS;
tx_header->data_len = args.output_buf_size; tx_header->data_len = args.output_buf_size;
tx_header->reserved = 0;
const uint16_t tx_valid_data_size = const uint16_t tx_valid_data_size =
tx_header->data_len + TX_HEADER_SIZE; tx_header->data_len + TX_HEADER_SIZE;
@ -192,6 +193,7 @@ static void handle_host_cmds_entry(void *arg1, void *arg2, void *arg3)
} }
/* Calculate checksum */ /* Calculate checksum */
tx_header->checksum = 0;
tx_header->checksum = tx_header->checksum =
cal_checksum(tx_buffer, tx_valid_data_size); cal_checksum(tx_buffer, tx_valid_data_size);
@ -199,6 +201,7 @@ static void handle_host_cmds_entry(void *arg1, void *arg2, void *arg3)
.buf = tx_buffer, .buf = tx_buffer,
.len = tx_valid_data_size, .len = tx_valid_data_size,
}; };
ec_host_cmd_periph_send(ec_host_cmd_dev, &tx); ec_host_cmd_periph_send(ec_host_cmd_dev, &tx);
} }
} }