Skip to content

Commit d1948dc

Browse files
niedzwiecki-dawidnashif
authored andcommitted
emul: espi: Add support for eSPI emulators
Add an emulation controller which routes eSPI traffic to attached emulators depending on the selected chip(mostly host). This allows drivers for eSPI peripherals to be tested on systems that don't have that peripheral attached, with the emulator handling the eSPI traffic. Signed-off-by: Dawid Niedzwiecki <[email protected]>
1 parent ff720cd commit d1948dc

File tree

8 files changed

+387
-0
lines changed

8 files changed

+387
-0
lines changed

boards/posix/native_posix/native_posix.dts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,15 @@
112112
label = "SPI_0";
113113
};
114114

115+
espi0: espi@300 {
116+
status = "okay";
117+
compatible = "zephyr,espi-emul-controller";
118+
reg = <0x300 4>;
119+
#address-cells = <1>;
120+
#size-cells = <0>;
121+
label = "ESPI_0";
122+
};
123+
115124
uart0: uart {
116125
status = "okay";
117126
compatible = "zephyr,native-posix-uart";

doc/guides/emulator/index.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ Zephyr includes the following emulators:
8585

8686
* SPI emulator driver, which does the same for SPI
8787

88+
* eSPI emulator driver, which does the same for eSPI. The emulator is being
89+
developed to support more functionalities.
90+
8891
A GPIO emulator is planned but is not yet complete.
8992

9093
Samples

drivers/espi/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ zephyr_library_sources_ifdef(CONFIG_ESPI_XEC espi_mchp_xec.c)
66
zephyr_library_sources_ifdef(CONFIG_ESPI_NPCX espi_npcx.c)
77
zephyr_library_sources_ifdef(CONFIG_ESPI_NPCX host_subs_npcx.c)
88
zephyr_library_sources_ifdef(CONFIG_USERSPACE espi_handlers.c)
9+
zephyr_library_sources_ifdef(CONFIG_ESPI_EMUL espi_emul.c)

drivers/espi/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ source "drivers/espi/Kconfig.xec"
1414

1515
source "drivers/espi/Kconfig.npcx"
1616

17+
source "drivers/espi/Kconfig.espi_emul"
18+
1719
module = ESPI
1820
module-str = espi
1921
source "subsys/logging/Kconfig.template.log_config"

drivers/espi/Kconfig.espi_emul

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Copyright 2020 Google LLC
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config ESPI_EMUL
5+
bool "eSPI emulator"
6+
help
7+
Enable the eSPI emulator driver. This is a fake driver,
8+
it does not talk to real hardware. Instead it talks to emulation
9+
drivers that pretend to be devices on the emulated eSPI bus. It is
10+
used for testing drivers for eSPI devices.
11+
12+
eSPI is an interface using SPI wires, whose main goal is to reduce the
13+
number of required pins. It includes the functionality of LPC, SMB, SPI
14+
itself (flash access) and GPIO (virtual wires). Please refer to the
15+
specification for more details (it is good for the introduction as well)
16+
https://www.intel.com/content/dam/support/us/en/documents/software/chipset-software/327432-004_espi_base_specification_rev1.0_cb.pdf

drivers/espi/espi_emul.c

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
/*
2+
* Copyright 2020 Google LLC
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* This driver creates fake eSPI buses which can contain emulated devices
7+
* (mainly host), implemented by a separate emulation driver.
8+
* The API between this driver/controller and device emulators attached
9+
* to its bus is defined by struct emul_espi_device_api.
10+
*/
11+
12+
#define DT_DRV_COMPAT zephyr_espi_emul_controller
13+
14+
#define LOG_LEVEL CONFIG_ESPI_LOG_LEVEL
15+
#include <logging/log.h>
16+
LOG_MODULE_REGISTER(espi_emul_ctlr);
17+
18+
#include <device.h>
19+
#include <emul.h>
20+
#include <drivers/espi.h>
21+
#include <drivers/espi_emul.h>
22+
#include "espi_utils.h"
23+
24+
/** Working data for the controller */
25+
struct espi_emul_data {
26+
/* List of struct espi_emul associated with the device */
27+
sys_slist_t emuls;
28+
/* eSPI host configuration */
29+
struct espi_cfg cfg;
30+
/** List of eSPI callbacks */
31+
sys_slist_t callbacks;
32+
};
33+
34+
static struct espi_emul *espi_emul_find(const struct device *dev,
35+
unsigned int chipsel)
36+
{
37+
struct espi_emul_data *data = dev->data;
38+
sys_snode_t *node;
39+
40+
SYS_SLIST_FOR_EACH_NODE(&data->emuls, node) {
41+
struct espi_emul *emul;
42+
43+
emul = CONTAINER_OF(node, struct espi_emul, node);
44+
if (emul->chipsel == chipsel) {
45+
return emul;
46+
}
47+
}
48+
49+
return NULL;
50+
}
51+
52+
static int espi_emul_config(const struct device *dev, struct espi_cfg *cfg)
53+
{
54+
struct espi_emul_data *data = dev->data;
55+
56+
__ASSERT_NO_MSG(cfg);
57+
58+
data->cfg = *cfg;
59+
60+
return 0;
61+
}
62+
63+
64+
static int emul_espi_trigger_event(const struct device *dev,
65+
struct espi_event *evt)
66+
{
67+
struct espi_emul_data *data = dev->data;
68+
69+
if (((evt->evt_type & ESPI_BUS_EVENT_VWIRE_RECEIVED) &&
70+
!(data->cfg.channel_caps & ESPI_CHANNEL_VWIRE)) ||
71+
((evt->evt_type & ESPI_BUS_EVENT_OOB_RECEIVED) &&
72+
!(data->cfg.channel_caps & ESPI_CHANNEL_OOB)) ||
73+
((evt->evt_type & ESPI_BUS_PERIPHERAL_NOTIFICATION)
74+
&& !(data->cfg.channel_caps & ESPI_CHANNEL_PERIPHERAL))) {
75+
return -EIO;
76+
}
77+
78+
espi_send_callbacks(&data->callbacks, dev, *evt);
79+
80+
return 0;
81+
}
82+
83+
static bool espi_emul_get_channel_status(const struct device *dev, enum espi_channel ch)
84+
{
85+
struct espi_emul_data *data = dev->data;
86+
87+
return (data->cfg.channel_caps & ch);
88+
}
89+
90+
static int espi_emul_send_vwire(const struct device *dev, enum espi_vwire_signal vw, uint8_t level)
91+
{
92+
const struct emul_espi_device_api *api;
93+
struct espi_emul *emul;
94+
struct espi_emul_data *data = dev->data;
95+
96+
if (!(data->cfg.channel_caps & ESPI_CHANNEL_VWIRE)) {
97+
return -EIO;
98+
}
99+
100+
emul = espi_emul_find(dev, EMUL_ESPI_HOST_CHIPSEL);
101+
if (!emul) {
102+
LOG_DBG("espi_emul not found");
103+
return -EIO;
104+
}
105+
106+
__ASSERT_NO_MSG(emul->api);
107+
__ASSERT_NO_MSG(emul->api->set_vw);
108+
api = emul->api;
109+
110+
return api->set_vw(emul, vw, level);
111+
}
112+
113+
static int espi_emul_receive_vwire(const struct device *dev, enum espi_vwire_signal vw, uint8_t *level)
114+
{
115+
const struct emul_espi_device_api *api;
116+
struct espi_emul *emul;
117+
struct espi_emul_data *data = dev->data;
118+
119+
if (!(data->cfg.channel_caps & ESPI_CHANNEL_VWIRE)) {
120+
return -EIO;
121+
}
122+
123+
emul = espi_emul_find(dev, EMUL_ESPI_HOST_CHIPSEL);
124+
if (!emul) {
125+
LOG_INF("espi_emul not found");
126+
return -EIO;
127+
}
128+
129+
__ASSERT_NO_MSG(emul->api);
130+
__ASSERT_NO_MSG(emul->api->get_vw);
131+
api = emul->api;
132+
133+
return api->get_vw(emul, vw, level);
134+
}
135+
136+
static int espi_emul_manage_callback(const struct device *dev, struct espi_callback *callback, bool set)
137+
{
138+
struct espi_emul_data *data = dev->data;
139+
140+
return espi_manage_callback(&data->callbacks, callback, set);
141+
}
142+
143+
/**
144+
* Set up a new emulator and add it to the list
145+
*
146+
* @param dev eSPI emulation controller device
147+
*/
148+
static int espi_emul_init(const struct device *dev)
149+
{
150+
struct espi_emul_data *data = dev->data;
151+
const struct emul_list_for_bus *list = dev->config;
152+
153+
sys_slist_init(&data->emuls);
154+
155+
return emul_init_for_bus_from_list(dev, list);
156+
}
157+
158+
int espi_emul_register(const struct device *dev, const char *name,
159+
struct espi_emul *emul)
160+
{
161+
struct espi_emul_data *data = dev->data;
162+
163+
sys_slist_append(&data->emuls, &emul->node);
164+
165+
LOG_INF("Register emulator '%s' at cs %u\n", name, emul->chipsel);
166+
167+
return 0;
168+
}
169+
170+
/* Device instantiation */
171+
static struct emul_espi_driver_api emul_espi_driver_api = {
172+
.espi_api = {
173+
.config = espi_emul_config,
174+
.get_channel_status = espi_emul_get_channel_status,
175+
.send_vwire = espi_emul_send_vwire,
176+
.receive_vwire = espi_emul_receive_vwire,
177+
.manage_callback = espi_emul_manage_callback
178+
},
179+
.trigger_event = emul_espi_trigger_event,
180+
.find_emul = espi_emul_find,
181+
};
182+
183+
184+
#define EMUL_LINK_AND_COMMA(node_id) { \
185+
.label = DT_LABEL(node_id), \
186+
},
187+
188+
#define ESPI_EMUL_INIT(n) \
189+
static const struct emul_link_for_bus emuls_##n[] = { \
190+
DT_FOREACH_CHILD(DT_DRV_INST(n), EMUL_LINK_AND_COMMA) \
191+
}; \
192+
static struct emul_list_for_bus espi_emul_cfg_##n = { \
193+
.children = emuls_##n, \
194+
.num_children = ARRAY_SIZE(emuls_##n), \
195+
}; \
196+
static struct espi_emul_data espi_emul_data_##n; \
197+
DEVICE_DT_INST_DEFINE(n, \
198+
&espi_emul_init, \
199+
device_pm_control_nop, \
200+
&espi_emul_data_##n, \
201+
&espi_emul_cfg_##n, \
202+
POST_KERNEL, \
203+
CONFIG_ESPI_INIT_PRIORITY, \
204+
&emul_espi_driver_api);
205+
206+
207+
DT_INST_FOREACH_STATUS_OKAY(ESPI_EMUL_INIT)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Copyright 2020 Google LLC
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: Zephyr eSPI Emulation controller
5+
6+
compatible: "zephyr,espi-emul-controller"
7+
8+
include: espi-controller.yaml
9+
10+
properties:
11+
reg:
12+
required: true

0 commit comments

Comments
 (0)