zephyr/subsys/emul/espi/emul_espi_host.c
Jose Alberto Meza 30eda2058b treewide: drivers: espi: Adjust terms per eSPI specification 1.5
1) Replace master/slave in API for new terms in eSPI spec 1.5
2) Reflect eSPI VW change and macro changes across eSPI drivers
3) Update terms in eSPI driver sample and eSPI test driver

Signed-off-by: Jose Alberto Meza <jose.a.meza.arellano@intel.com>
2024-05-02 13:56:46 -04:00

270 lines
7.7 KiB
C

/*
* Copyright 2020 Google LLC
*
* SPDX-License-Identifier: Apache-2.0
*
* Emulator for the generic eSPI Host. This supports basic
* host operations.
*/
#define DT_DRV_COMPAT zephyr_espi_emul_espi_host
#define LOG_LEVEL CONFIG_ESPI_LOG_LEVEL
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(espi_host);
#include <zephyr/device.h>
#include <zephyr/drivers/emul.h>
#include <zephyr/drivers/espi.h>
#include <zephyr/drivers/espi_emul.h>
/** Data about the virtual wire */
struct vw_data {
/* Virtual wire signal */
enum espi_vwire_signal sig;
/* The level(state) of the virtual wire */
uint8_t level;
/* The direction of the virtual wire. Possible values:
* ESPI_CONTROLLER_TO_TARGET or ESPI_TARGET_TO_CONTROLLER
*/
uint8_t dir;
};
/** Declare the default state of virtual wires */
const static struct vw_data vw_state_default[] = {
{ ESPI_VWIRE_SIGNAL_SLP_S3, 0, ESPI_CONTROLLER_TO_TARGET },
{ ESPI_VWIRE_SIGNAL_SLP_S4, 0, ESPI_CONTROLLER_TO_TARGET },
{ ESPI_VWIRE_SIGNAL_SLP_S5, 0, ESPI_CONTROLLER_TO_TARGET },
{ ESPI_VWIRE_SIGNAL_SUS_STAT, 0, ESPI_CONTROLLER_TO_TARGET },
{ ESPI_VWIRE_SIGNAL_PLTRST, 0, ESPI_CONTROLLER_TO_TARGET },
{ ESPI_VWIRE_SIGNAL_OOB_RST_WARN, 0, ESPI_CONTROLLER_TO_TARGET },
{ ESPI_VWIRE_SIGNAL_OOB_RST_ACK, 0, ESPI_TARGET_TO_CONTROLLER },
{ ESPI_VWIRE_SIGNAL_WAKE, 0, ESPI_TARGET_TO_CONTROLLER },
{ ESPI_VWIRE_SIGNAL_PME, 0, ESPI_TARGET_TO_CONTROLLER },
{ ESPI_VWIRE_SIGNAL_TARGET_BOOT_DONE, 0, ESPI_TARGET_TO_CONTROLLER },
{ ESPI_VWIRE_SIGNAL_ERR_FATAL, 0, ESPI_TARGET_TO_CONTROLLER },
{ ESPI_VWIRE_SIGNAL_ERR_NON_FATAL, 0, ESPI_TARGET_TO_CONTROLLER },
{ ESPI_VWIRE_SIGNAL_TARGET_BOOT_STS, 0, ESPI_TARGET_TO_CONTROLLER },
{ ESPI_VWIRE_SIGNAL_SCI, 0, ESPI_TARGET_TO_CONTROLLER },
{ ESPI_VWIRE_SIGNAL_SMI, 0, ESPI_TARGET_TO_CONTROLLER },
{ ESPI_VWIRE_SIGNAL_RST_CPU_INIT, 0, ESPI_TARGET_TO_CONTROLLER },
{ ESPI_VWIRE_SIGNAL_HOST_RST_ACK, 0, ESPI_TARGET_TO_CONTROLLER },
{ ESPI_VWIRE_SIGNAL_HOST_RST_WARN, 0, ESPI_CONTROLLER_TO_TARGET },
{ ESPI_VWIRE_SIGNAL_SUS_ACK, 0, ESPI_TARGET_TO_CONTROLLER },
{ ESPI_VWIRE_SIGNAL_DNX_ACK, 0, ESPI_TARGET_TO_CONTROLLER },
{ ESPI_VWIRE_SIGNAL_SUS_WARN, 0, ESPI_CONTROLLER_TO_TARGET },
{ ESPI_VWIRE_SIGNAL_SUS_PWRDN_ACK, 0, ESPI_CONTROLLER_TO_TARGET },
{ ESPI_VWIRE_SIGNAL_SLP_A, 0, ESPI_CONTROLLER_TO_TARGET },
{ ESPI_VWIRE_SIGNAL_SLP_LAN, 0, ESPI_CONTROLLER_TO_TARGET },
{ ESPI_VWIRE_SIGNAL_SLP_WLAN, 0, ESPI_CONTROLLER_TO_TARGET },
{ ESPI_VWIRE_SIGNAL_HOST_C10, 0, ESPI_CONTROLLER_TO_TARGET },
{ ESPI_VWIRE_SIGNAL_DNX_WARN, 0, ESPI_CONTROLLER_TO_TARGET },
};
#define NUMBER_OF_VWIRES ARRAY_SIZE(vw_state_default)
/** Run-time data used by the emulator */
struct espi_host_emul_data {
/** eSPI emulator detail */
struct espi_emul emul;
/** eSPI controller device */
const struct device *espi;
/** Virtual Wires states, for one slave only.
* With multi-slaves config, the states should be saved per slave */
struct vw_data vw_state[NUMBER_OF_VWIRES];
#ifdef CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION
/** ACPI Shared memory. */
uint8_t shm_acpi_mmap[CONFIG_EMUL_ESPI_HOST_ACPI_SHM_REGION_SIZE];
#endif
};
/** Static configuration for the emulator */
struct espi_host_emul_cfg {
/** Label of the emulated AP*/
const char *label;
/* eSPI chip-select of the emulated device */
uint16_t chipsel;
};
/**
* Initialize the state of virtual wires to default based on
* the vw_state_default array.
*
* @param data Host emulator data with the vwire array
*/
static void emul_host_init_vw_state(struct espi_host_emul_data *data)
{
unsigned i;
for (i = 0; i < NUMBER_OF_VWIRES; i++) {
data->vw_state[i] = vw_state_default[i];
}
return;
}
/**
* Find a virtual wire in the array placed in the host data.
*
* @param data Host emulator data with the vwire array
* @param vw Virtual wire signal to be found
* @return index in the array
* @return -1 if not found
*/
static int emul_host_find_index(struct espi_host_emul_data *data,
enum espi_vwire_signal vw)
{
int idx;
for (idx = 0; idx < NUMBER_OF_VWIRES; idx++) {
if (data->vw_state[idx].sig == vw) {
return idx;
}
}
return -1;
}
static int emul_host_set_vw(const struct emul *target,
enum espi_vwire_signal vw, uint8_t level)
{
struct espi_host_emul_data *data = target->data;
int idx;
idx = emul_host_find_index(data, vw);
if (idx < 0 || data->vw_state[idx].dir != ESPI_TARGET_TO_CONTROLLER) {
LOG_ERR("%s: invalid vw: %d", __func__, vw);
return -EPERM;
}
data->vw_state[idx].level = level;
return 0;
}
static int emul_host_get_vw(const struct emul *target,
enum espi_vwire_signal vw, uint8_t *level)
{
struct espi_host_emul_data *data = target->data;
int idx;
idx = emul_host_find_index(data, vw);
if (idx < 0 || data->vw_state[idx].dir != ESPI_CONTROLLER_TO_TARGET) {
LOG_ERR("%s: invalid vw: %d", __func__, vw);
return -EPERM;
}
*level = data->vw_state[idx].level;
return 0;
}
int emul_espi_host_send_vw(const struct device *espi_dev, enum espi_vwire_signal vw,
uint8_t level)
{
struct espi_emul *emul_espi;
struct espi_event evt;
struct espi_host_emul_data *data_host;
struct emul_espi_driver_api *api;
int idx;
api = (struct emul_espi_driver_api *)espi_dev->api;
__ASSERT_NO_MSG(api);
__ASSERT_NO_MSG(api->trigger_event);
__ASSERT_NO_MSG(api->find_emul);
emul_espi = api->find_emul(espi_dev, EMUL_ESPI_HOST_CHIPSEL);
data_host = emul_espi->target->data;
idx = emul_host_find_index(data_host, vw);
if (idx < 0 || data_host->vw_state[idx].dir != ESPI_CONTROLLER_TO_TARGET) {
LOG_ERR("%s: invalid vw: %d", __func__, vw);
return -EPERM;
}
data_host->vw_state[idx].level = level;
evt.evt_type = ESPI_BUS_EVENT_VWIRE_RECEIVED;
evt.evt_details = vw;
evt.evt_data = level;
api->trigger_event(espi_dev, &evt);
return 0;
}
int emul_espi_host_port80_write(const struct device *espi_dev, uint32_t data)
{
struct espi_event evt;
struct emul_espi_driver_api *api;
api = (struct emul_espi_driver_api *)espi_dev->api;
__ASSERT_NO_MSG(api);
__ASSERT_NO_MSG(api->trigger_event);
evt.evt_type = ESPI_BUS_PERIPHERAL_NOTIFICATION;
evt.evt_details = ESPI_PERIPHERAL_DEBUG_PORT80;
evt.evt_data = data;
api->trigger_event(espi_dev, &evt);
return 0;
}
#ifdef CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION
static uintptr_t emul_espi_dev_get_acpi_shm(const struct emul *target)
{
struct espi_host_emul_data *data = target->data;
return (uintptr_t)data->shm_acpi_mmap;
}
uintptr_t emul_espi_host_get_acpi_shm(const struct device *espi_dev)
{
uint32_t shm;
int rc = espi_read_lpc_request(espi_dev, EACPI_GET_SHARED_MEMORY, &shm);
__ASSERT_NO_MSG(rc == 0);
return (uintptr_t) shm;
}
#endif
/* Device instantiation */
static struct emul_espi_device_api ap_emul_api = {
.set_vw = emul_host_set_vw,
.get_vw = emul_host_get_vw,
.get_acpi_shm = emul_espi_dev_get_acpi_shm,
};
/**
* Set up a new eSPI host emulator
*
* @param emul Emulation information
* @param bus Device to emulated eSPI controller
* @return 0 indicating success (always)
*/
static int emul_host_init(const struct emul *emul, const struct device *bus)
{
struct espi_host_emul_data *data = emul->data;
ARG_UNUSED(bus);
emul_host_init_vw_state(data);
return 0;
}
#define HOST_EMUL(n) \
static struct espi_host_emul_data espi_host_emul_data_##n; \
static const struct espi_host_emul_cfg espi_host_emul_cfg_##n = { \
.chipsel = DT_INST_REG_ADDR(n), \
}; \
EMUL_DT_INST_DEFINE(n, emul_host_init, &espi_host_emul_data_##n, &espi_host_emul_cfg_##n, \
&ap_emul_api, NULL)
DT_INST_FOREACH_STATUS_OKAY(HOST_EMUL)