Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions boards/posix/native_posix/native_posix.dts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,15 @@
label = "SPI_0";
};

espi0: espi@300 {
status = "okay";
compatible = "zephyr,espi-emul-controller";
reg = <0x300 4>;
#address-cells = <1>;
#size-cells = <0>;
label = "ESPI_0";
};

uart0: uart {
status = "okay";
compatible = "zephyr,native-posix-uart";
Expand Down
3 changes: 3 additions & 0 deletions doc/guides/emulator/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ Zephyr includes the following emulators:

* SPI emulator driver, which does the same for SPI

* eSPI emulator driver, which does the same for eSPI. The emulator is being
developed to support more functionalities.

A GPIO emulator is planned but is not yet complete.

Samples
Expand Down
1 change: 1 addition & 0 deletions drivers/espi/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ zephyr_library_sources_ifdef(CONFIG_ESPI_XEC espi_mchp_xec.c)
zephyr_library_sources_ifdef(CONFIG_ESPI_NPCX espi_npcx.c)
zephyr_library_sources_ifdef(CONFIG_ESPI_NPCX host_subs_npcx.c)
zephyr_library_sources_ifdef(CONFIG_USERSPACE espi_handlers.c)
zephyr_library_sources_ifdef(CONFIG_ESPI_EMUL espi_emul.c)
2 changes: 2 additions & 0 deletions drivers/espi/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ source "drivers/espi/Kconfig.xec"

source "drivers/espi/Kconfig.npcx"

source "drivers/espi/Kconfig.espi_emul"

module = ESPI
module-str = espi
source "subsys/logging/Kconfig.template.log_config"
Expand Down
16 changes: 16 additions & 0 deletions drivers/espi/Kconfig.espi_emul
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright 2020 Google LLC
# SPDX-License-Identifier: Apache-2.0

config ESPI_EMUL
bool "eSPI emulator"
help
Enable the eSPI emulator driver. This is a fake driver,
it does not talk to real hardware. Instead it talks to emulation
drivers that pretend to be devices on the emulated eSPI bus. It is
used for testing drivers for eSPI devices.

eSPI is an interface using SPI wires, whose main goal is to reduce the
number of required pins. It includes the functionality of LPC, SMB, SPI
itself (flash access) and GPIO (virtual wires). Please refer to the
specification for more details (it is good for the introduction as well)
https://www.intel.com/content/dam/support/us/en/documents/software/chipset-software/327432-004_espi_base_specification_rev1.0_cb.pdf
207 changes: 207 additions & 0 deletions drivers/espi/espi_emul.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
/*
* Copyright 2020 Google LLC
*
* SPDX-License-Identifier: Apache-2.0
*
* This driver creates fake eSPI buses which can contain emulated devices
* (mainly host), implemented by a separate emulation driver.
* The API between this driver/controller and device emulators attached
* to its bus is defined by struct emul_espi_device_api.
*/

#define DT_DRV_COMPAT zephyr_espi_emul_controller

#define LOG_LEVEL CONFIG_ESPI_LOG_LEVEL
#include <logging/log.h>
LOG_MODULE_REGISTER(espi_emul_ctlr);

#include <device.h>
#include <emul.h>
#include <drivers/espi.h>
#include <drivers/espi_emul.h>
#include "espi_utils.h"

/** Working data for the controller */
struct espi_emul_data {
/* List of struct espi_emul associated with the device */
sys_slist_t emuls;
/* eSPI host configuration */
struct espi_cfg cfg;
/** List of eSPI callbacks */
sys_slist_t callbacks;
};

static struct espi_emul *espi_emul_find(const struct device *dev,
unsigned int chipsel)
{
struct espi_emul_data *data = dev->data;
sys_snode_t *node;

SYS_SLIST_FOR_EACH_NODE(&data->emuls, node) {
struct espi_emul *emul;

emul = CONTAINER_OF(node, struct espi_emul, node);
if (emul->chipsel == chipsel) {
return emul;
}
}

return NULL;
}

static int espi_emul_config(const struct device *dev, struct espi_cfg *cfg)
{
struct espi_emul_data *data = dev->data;

__ASSERT_NO_MSG(cfg);

data->cfg = *cfg;

return 0;
}


static int emul_espi_trigger_event(const struct device *dev,
struct espi_event *evt)
{
struct espi_emul_data *data = dev->data;

if (((evt->evt_type & ESPI_BUS_EVENT_VWIRE_RECEIVED) &&
!(data->cfg.channel_caps & ESPI_CHANNEL_VWIRE)) ||
((evt->evt_type & ESPI_BUS_EVENT_OOB_RECEIVED) &&
!(data->cfg.channel_caps & ESPI_CHANNEL_OOB)) ||
((evt->evt_type & ESPI_BUS_PERIPHERAL_NOTIFICATION)
&& !(data->cfg.channel_caps & ESPI_CHANNEL_PERIPHERAL))) {
return -EIO;
}

espi_send_callbacks(&data->callbacks, dev, *evt);

return 0;
}

static bool espi_emul_get_channel_status(const struct device *dev, enum espi_channel ch)
{
struct espi_emul_data *data = dev->data;

return (data->cfg.channel_caps & ch);
}

static int espi_emul_send_vwire(const struct device *dev, enum espi_vwire_signal vw, uint8_t level)
{
const struct emul_espi_device_api *api;
struct espi_emul *emul;
struct espi_emul_data *data = dev->data;

if (!(data->cfg.channel_caps & ESPI_CHANNEL_VWIRE)) {
return -EIO;
}

emul = espi_emul_find(dev, EMUL_ESPI_HOST_CHIPSEL);
if (!emul) {
LOG_DBG("espi_emul not found");
return -EIO;
}

__ASSERT_NO_MSG(emul->api);
__ASSERT_NO_MSG(emul->api->set_vw);
api = emul->api;

return api->set_vw(emul, vw, level);
}

static int espi_emul_receive_vwire(const struct device *dev, enum espi_vwire_signal vw, uint8_t *level)
{
const struct emul_espi_device_api *api;
struct espi_emul *emul;
struct espi_emul_data *data = dev->data;

if (!(data->cfg.channel_caps & ESPI_CHANNEL_VWIRE)) {
return -EIO;
}

emul = espi_emul_find(dev, EMUL_ESPI_HOST_CHIPSEL);
if (!emul) {
LOG_INF("espi_emul not found");
return -EIO;
}

__ASSERT_NO_MSG(emul->api);
__ASSERT_NO_MSG(emul->api->get_vw);
api = emul->api;

return api->get_vw(emul, vw, level);
}

static int espi_emul_manage_callback(const struct device *dev, struct espi_callback *callback, bool set)
{
struct espi_emul_data *data = dev->data;

return espi_manage_callback(&data->callbacks, callback, set);
}

/**
* Set up a new emulator and add it to the list
*
* @param dev eSPI emulation controller device
*/
static int espi_emul_init(const struct device *dev)
{
struct espi_emul_data *data = dev->data;
const struct emul_list_for_bus *list = dev->config;

sys_slist_init(&data->emuls);

return emul_init_for_bus_from_list(dev, list);
}

int espi_emul_register(const struct device *dev, const char *name,
struct espi_emul *emul)
{
struct espi_emul_data *data = dev->data;

sys_slist_append(&data->emuls, &emul->node);

LOG_INF("Register emulator '%s' at cs %u\n", name, emul->chipsel);

return 0;
}

/* Device instantiation */
static struct emul_espi_driver_api emul_espi_driver_api = {
.espi_api = {
.config = espi_emul_config,
.get_channel_status = espi_emul_get_channel_status,
.send_vwire = espi_emul_send_vwire,
.receive_vwire = espi_emul_receive_vwire,
.manage_callback = espi_emul_manage_callback
},
.trigger_event = emul_espi_trigger_event,
.find_emul = espi_emul_find,
};


#define EMUL_LINK_AND_COMMA(node_id) { \
.label = DT_LABEL(node_id), \
},

#define ESPI_EMUL_INIT(n) \
static const struct emul_link_for_bus emuls_##n[] = { \
DT_FOREACH_CHILD(DT_DRV_INST(n), EMUL_LINK_AND_COMMA) \
}; \
static struct emul_list_for_bus espi_emul_cfg_##n = { \
.children = emuls_##n, \
.num_children = ARRAY_SIZE(emuls_##n), \
}; \
static struct espi_emul_data espi_emul_data_##n; \
DEVICE_DT_INST_DEFINE(n, \
&espi_emul_init, \
device_pm_control_nop, \
&espi_emul_data_##n, \
&espi_emul_cfg_##n, \
POST_KERNEL, \
CONFIG_ESPI_INIT_PRIORITY, \
&emul_espi_driver_api);


DT_INST_FOREACH_STATUS_OKAY(ESPI_EMUL_INIT)
12 changes: 12 additions & 0 deletions dts/bindings/espi/zephyr,espi-emul.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright 2020 Google LLC
# SPDX-License-Identifier: Apache-2.0

description: Zephyr eSPI Emulation controller

compatible: "zephyr,espi-emul-controller"

include: espi-controller.yaml

properties:
reg:
required: true
Loading