summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJack Rosenthal <jrosenth@chromium.org>2020-11-11 12:30:51 -0700
committerCommit Bot <commit-bot@chromium.org>2020-11-20 20:32:32 +0000
commit4e1da5433feb066465bf49df13c1ec0995941e3f (patch)
tree6979d35e22732d5400481bbf1ad2cd803e346125
parent0be00eec2444f1c40ff0e39c0a35c55d46798885 (diff)
downloadchrome-ec-4e1da5433feb066465bf49df13c1ec0995941e3f.tar.gz
zephyr: shim some basic eSPI functionality
Add some basic functionality to get and set virtual wires. BUG=b:171815541 BRANCH=none TEST=volteer power sequencing to S0 (requires follow-up CLs) Signed-off-by: Jack Rosenthal <jrosenth@chromium.org> Change-Id: I07655fd3a768aca962112a98d6f1f593633eb605 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2548307 Reviewed-by: Jett Rink <jettrink@chromium.org>
-rw-r--r--zephyr/CMakeLists.txt1
-rw-r--r--zephyr/Kconfig23
-rw-r--r--zephyr/shim/include/config_chip.h9
-rw-r--r--zephyr/shim/include/zephyr_espi_shim.h16
-rw-r--r--zephyr/shim/src/CMakeLists.txt1
-rw-r--r--zephyr/shim/src/espi.c207
6 files changed, 257 insertions, 0 deletions
diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt
index 475834f7e7..7aeeaa6d28 100644
--- a/zephyr/CMakeLists.txt
+++ b/zephyr/CMakeLists.txt
@@ -35,6 +35,7 @@ zephyr_include_directories_ifdef(
add_subdirectory_ifdef(CONFIG_PLATFORM_EC "shim")
zephyr_sources_ifdef(CONFIG_PLATFORM_EC "${PLATFORM_EC}/common/base32.c")
+zephyr_sources_ifdef(CONFIG_PLATFORM_EC_ESPI "${PLATFORM_EC}/common/espi.c")
zephyr_sources_ifdef(CONFIG_PLATFORM_EC "${PLATFORM_EC}/common/extpower_common.c")
zephyr_sources_ifdef(CONFIG_PLATFORM_EC_EXTPOWER_GPIO
"${PLATFORM_EC}/common/extpower_gpio.c")
diff --git a/zephyr/Kconfig b/zephyr/Kconfig
index 60ac36c43a..fb1c4bfb0f 100644
--- a/zephyr/Kconfig
+++ b/zephyr/Kconfig
@@ -107,6 +107,29 @@ config PLATFORM_EC_TIMER_CMD_WAITMS
endif # PLATFORM_EC_TIMER
+menuconfig PLATFORM_EC_ESPI
+ bool "Enable eSPI compatibility in platform/ec"
+ depends on ESPI && AP
+ default y
+ help
+ Enable eSPI shim layer.
+
+if PLATFORM_EC_ESPI
+
+config PLATFORM_EC_ESPI_VW_SLP_S3
+ bool "SLP_S3 is an eSPI virtual wire instead of a GPIO"
+ help
+ For power sequencing, use an eSPI virtual wire instead of
+ defining GPIO_PCH_SLP_S3 in gpio_map.h.
+
+config PLATFORM_EC_ESPI_VW_SLP_S4
+ bool "SLP_S4 is an eSPI virtual wire instead of a GPIO"
+ help
+ For power sequencing, use an eSPI virtual wire instead of
+ defining GPIO_PCH_SLP_S4 in gpio_map.h.
+
+endif # PLATFORM_EC_ESPI
+
config PLATFORM_EC_HOOKS
bool "Enable hooks and deferred compatibility shim"
default y
diff --git a/zephyr/shim/include/config_chip.h b/zephyr/shim/include/config_chip.h
index 64c8afc2ab..8995edd68b 100644
--- a/zephyr/shim/include/config_chip.h
+++ b/zephyr/shim/include/config_chip.h
@@ -53,6 +53,15 @@
#endif /* CONFIG_PLATFORM_EC_TIMER */
+/* eSPI signals */
+#ifdef CONFIG_PLATFORM_EC_ESPI_VW_SLP_S3
+#define CONFIG_HOSTCMD_ESPI_VW_SLP_S3
+#endif
+
+#ifdef CONFIG_PLATFORM_EC_ESPI_VW_SLP_S4
+#define CONFIG_HOSTCMD_ESPI_VW_SLP_S4
+#endif
+
/*
* Load the chip family specific header. Normally for npcx, this would be done
* by chip/npcx/config_chip.h but since this file is replacing that header
diff --git a/zephyr/shim/include/zephyr_espi_shim.h b/zephyr/shim/include/zephyr_espi_shim.h
new file mode 100644
index 0000000000..c8172e8653
--- /dev/null
+++ b/zephyr/shim/include/zephyr_espi_shim.h
@@ -0,0 +1,16 @@
+/* Copyright 2020 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef __CROS_EC_ZEPHYR_ESPI_SHIM_H
+#define __CROS_EC_ZEPHYR_ESPI_SHIM_H
+
+/**
+ * zephyr_shim_setup_espi() - initialize eSPI device
+ *
+ * Return: 0 upon success, or <0 upon failure.
+ */
+int zephyr_shim_setup_espi(void);
+
+#endif /* __CROS_EC_ZEPHYR_ESPI_SHIM_H */
diff --git a/zephyr/shim/src/CMakeLists.txt b/zephyr/shim/src/CMakeLists.txt
index b3a828b412..a8f9a636d5 100644
--- a/zephyr/shim/src/CMakeLists.txt
+++ b/zephyr/shim/src/CMakeLists.txt
@@ -7,6 +7,7 @@ zephyr_sources(gpio.c)
zephyr_sources(util.c)
zephyr_sources(crc.c)
+zephyr_sources_ifdef(CONFIG_PLATFORM_EC_ESPI espi.c)
zephyr_sources_ifdef(CONFIG_PLATFORM_EC_HOOKS hooks.c)
zephyr_sources_ifdef(CONFIG_PLATFORM_EC_TIMER hwtimer.c)
zephyr_sources_ifdef(CONFIG_PLATFORM_EC_I2C i2c.c)
diff --git a/zephyr/shim/src/espi.c b/zephyr/shim/src/espi.c
new file mode 100644
index 0000000000..ceeed83b79
--- /dev/null
+++ b/zephyr/shim/src/espi.c
@@ -0,0 +1,207 @@
+/* Copyright 2020 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <atomic.h>
+#include <device.h>
+#include <drivers/espi.h>
+#include <logging/log.h>
+#include <kernel.h>
+#include <stdint.h>
+#include <zephyr.h>
+
+#include "chipset.h"
+#include "espi.h"
+#include "port80.h"
+#include "zephyr_espi_shim.h"
+
+LOG_MODULE_REGISTER(espi_shim, CONFIG_ESPI_LOG_LEVEL);
+
+/*
+ * A mapping of platform/ec signals to Zephyr virtual wires.
+ *
+ * This should be a macro which takes a parameter M, and does a
+ * functional application of M to 2-tuples of (platform/ec signal,
+ * zephyr vwire).
+ */
+#define VW_SIGNAL_TRANSLATION_LIST(M) \
+ M(VW_SLP_S3_L, ESPI_VWIRE_SIGNAL_SLP_S3) \
+ M(VW_SLP_S4_L, ESPI_VWIRE_SIGNAL_SLP_S4) \
+ M(VW_SLP_S5_L, ESPI_VWIRE_SIGNAL_SLP_S5) \
+ M(VW_SUS_STAT_L, ESPI_VWIRE_SIGNAL_SUS_STAT) \
+ M(VW_PLTRST_L, ESPI_VWIRE_SIGNAL_PLTRST) \
+ M(VW_OOB_RST_WARN, ESPI_VWIRE_SIGNAL_OOB_RST_WARN) \
+ M(VW_OOB_RST_ACK, ESPI_VWIRE_SIGNAL_OOB_RST_ACK) \
+ M(VW_WAKE_L, ESPI_VWIRE_SIGNAL_WAKE) \
+ M(VW_PME_L, ESPI_VWIRE_SIGNAL_PME) \
+ M(VW_ERROR_FATAL, ESPI_VWIRE_SIGNAL_ERR_FATAL) \
+ M(VW_ERROR_NON_FATAL, ESPI_VWIRE_SIGNAL_ERR_NON_FATAL) \
+ M(VW_SLAVE_BTLD_STATUS_DONE, ESPI_VWIRE_SIGNAL_SLV_BOOT_DONE) \
+ M(VW_SCI_L, ESPI_VWIRE_SIGNAL_SCI) \
+ M(VW_SMI_L, ESPI_VWIRE_SIGNAL_SMI) \
+ M(VW_HOST_RST_ACK, ESPI_VWIRE_SIGNAL_HOST_RST_ACK) \
+ M(VW_HOST_RST_WARN, ESPI_VWIRE_SIGNAL_HOST_RST_WARN) \
+ M(VW_SUS_ACK, ESPI_VWIRE_SIGNAL_SUS_ACK) \
+ M(VW_SUS_WARN_L, ESPI_VWIRE_SIGNAL_SUS_WARN) \
+ M(VW_SUS_PWRDN_ACK_L, ESPI_VWIRE_SIGNAL_SUS_PWRDN_ACK) \
+ M(VW_SLP_A_L, ESPI_VWIRE_SIGNAL_SLP_A) \
+ M(VW_SLP_LAN, ESPI_VWIRE_SIGNAL_SLP_LAN) \
+ M(VW_SLP_WLAN, ESPI_VWIRE_SIGNAL_SLP_WLAN)
+
+/*
+ * These two macros are intended to be used as as the M parameter to
+ * the list above, generating case statements returning the
+ * translation for the first parameter to the second, and the second
+ * to the first, respectively.
+ */
+#define CASE_CROS_TO_ZEPHYR(A, B) \
+ case A: \
+ return B;
+#define CASE_ZEPHYR_TO_CROS(A, B) CASE_CROS_TO_ZEPHYR(B, A)
+
+/* Translate a platform/ec signal to a Zephyr signal */
+static enum espi_vwire_signal signal_to_zephyr_vwire(enum espi_vw_signal signal)
+{
+ switch (signal) {
+ VW_SIGNAL_TRANSLATION_LIST(CASE_CROS_TO_ZEPHYR);
+ default:
+ LOG_ERR("Invalid virtual wire signal (%d)", signal);
+ return -1;
+ }
+}
+
+/* Translate a Zephyr vwire to a platform/ec signal */
+static enum espi_vw_signal zephyr_vwire_to_signal(enum espi_vwire_signal vwire)
+{
+ switch (vwire) {
+ VW_SIGNAL_TRANSLATION_LIST(CASE_ZEPHYR_TO_CROS);
+ default:
+ LOG_ERR("Invalid zephyr vwire (%d)", vwire);
+ return -1;
+ }
+}
+
+/*
+ * Bit field for each signal which can have an interrupt enabled.
+ * Note the interrupt is always enabled, it just depends whether we
+ * route it to the power_signal_interrupt handler or not.
+ */
+static atomic_t signal_interrupt_enabled;
+
+/* To be used with VW_SIGNAL_TRASLATION_LIST */
+#define CASE_CROS_TO_BIT(A, _) CASE_CROS_TO_ZEPHYR(A, BIT(A - VW_SIGNAL_START))
+
+/* Convert from an EC signal to the corresponding interrupt enabled bit. */
+static uint32_t signal_to_interrupt_bit(enum espi_vw_signal signal)
+{
+ switch (signal) {
+ VW_SIGNAL_TRANSLATION_LIST(CASE_CROS_TO_BIT);
+ default:
+ return 0;
+ }
+}
+
+/* Callback for vwire received */
+static void espi_vwire_handler(const struct device *dev,
+ struct espi_callback *cb,
+ struct espi_event event)
+{
+ int ec_signal = zephyr_vwire_to_signal(event.evt_details);
+
+ if (IS_ENABLED(CONFIG_PLATFORM_EC_POWERseQ) &&
+ (signal_interrupt_enabled & signal_to_interrupt_bit(ec_signal))) {
+ power_signal_interrupt(ec_signal);
+ }
+}
+
+static void espi_peripheral_handler(const struct device *dev,
+ struct espi_callback *cb,
+ struct espi_event event)
+{
+ uint16_t event_type = event.evt_details;
+
+ if (IS_ENABLED(CONFIG_PLATFORM_EC_PORT80) &&
+ event_type == ESPI_PERIPHERAL_DEBUG_PORT80) {
+ port_80_write(event.evt_data);
+ }
+}
+
+#define ESPI_DEV DT_LABEL(DT_NODELABEL(espi0))
+static const struct device *espi_dev;
+
+int zephyr_shim_setup_espi(void)
+{
+ static struct {
+ struct espi_callback cb;
+ espi_callback_handler_t handler;
+ enum espi_bus_event event_type;
+ } callbacks[] = {
+ {
+ .handler = espi_vwire_handler,
+ .event_type = ESPI_BUS_EVENT_VWIRE_RECEIVED,
+ },
+ {
+ .handler = espi_peripheral_handler,
+ .event_type = ESPI_BUS_PERIPHERAL_NOTIFICATION,
+ },
+ };
+
+ struct espi_cfg cfg = {
+ .io_caps = ESPI_IO_MODE_SINGLE_LINE,
+ .channel_caps = ESPI_CHANNEL_VWIRE | ESPI_CHANNEL_PERIPHERAL |
+ ESPI_CHANNEL_OOB,
+ .max_freq = 20,
+ };
+
+ espi_dev = device_get_binding(ESPI_DEV);
+ if (!espi_dev) {
+ LOG_ERR("Failed to find device %s", ESPI_DEV);
+ return -1;
+ }
+
+ /* Configure eSPI */
+ if (espi_config(espi_dev, &cfg)) {
+ LOG_ERR("Failed to configure eSPI device");
+ return -1;
+ }
+
+ /* Setup callbacks */
+ for (size_t i = 0; i < ARRAY_SIZE(callbacks); i++) {
+ espi_init_callback(&callbacks[i].cb, callbacks[i].handler,
+ callbacks[i].event_type);
+ espi_add_callback(espi_dev, &callbacks[i].cb);
+ }
+
+ return 0;
+}
+
+int espi_vw_set_wire(enum espi_vw_signal signal, uint8_t level)
+{
+ return espi_send_vwire(espi_dev, signal_to_zephyr_vwire(signal), level);
+}
+
+int espi_vw_get_wire(enum espi_vw_signal signal)
+{
+ uint8_t level;
+
+ if (espi_receive_vwire(espi_dev, signal_to_zephyr_vwire(signal),
+ &level) < 0) {
+ LOG_ERR("Encountered error receiving virtual wire signal");
+ return 0;
+ }
+
+ return level;
+}
+
+int espi_vw_enable_wire_int(enum espi_vw_signal signal)
+{
+ atomic_or(signal_interrupt_enabled, signal_to_interrupt_bit(signal));
+ return 0;
+}
+
+int espi_vw_disable_wire_int(enum espi_vw_signal signal)
+{
+ atomic_and(signal_interrupt_enabled, ~signal_to_interrupt_bit(signal));
+ return 0;
+}