summaryrefslogtreecommitdiff
path: root/zephyr/shim/src/espi.c
diff options
context:
space:
mode:
Diffstat (limited to 'zephyr/shim/src/espi.c')
-rw-r--r--zephyr/shim/src/espi.c291
1 files changed, 212 insertions, 79 deletions
diff --git a/zephyr/shim/src/espi.c b/zephyr/shim/src/espi.c
index 74f6b70f42..d6f6bed314 100644
--- a/zephyr/shim/src/espi.c
+++ b/zephyr/shim/src/espi.c
@@ -1,4 +1,4 @@
-/* Copyright 2020 The Chromium OS Authors. All rights reserved.
+/* Copyright 2020 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -10,10 +10,10 @@
#include <zephyr/logging/log.h>
#include <zephyr/kernel.h>
#include <stdint.h>
-#include <zephyr/zephyr.h>
#include <ap_power/ap_power.h>
#include <ap_power/ap_power_events.h>
+#include <ap_power/ap_power_espi.h>
#include "acpi.h"
#include "chipset.h"
#include "common.h"
@@ -28,10 +28,29 @@
#include "timer.h"
#include "zephyr_espi_shim.h"
-#define VWIRE_PULSE_TRIGGER_TIME CONFIG_PLATFORM_EC_ESPI_DEFAULT_VW_WIDTH_US
+#define VWIRE_PULSE_TRIGGER_TIME \
+ CONFIG_PLATFORM_EC_HOST_INTERFACE_ESPI_DEFAULT_VW_WIDTH_US
LOG_MODULE_REGISTER(espi_shim, CONFIG_ESPI_LOG_LEVEL);
+/*
+ * Some functions are compiled depending on combinations of
+ * CONFIG_PLATFORM_EC_POWERSEQ, CONFIG_AP_PWRSEQ and
+ * CONFIG_PLATFORM_EC_CHIPSET_RESET_HOOK.
+ *
+ * Tests are compiled without CONFIG_PLATFORM_EC_POWERSEQ and
+ * CONFIG_AP_PWRSEQ defined, but use the lpc functions.
+ *
+ * Legacy vwire power signal handling is required
+ * by CONFIG_PLATFORM_EC_POWERSEQ.
+ *
+ * CONFIG_PLATFORM_EC_CHIPSET_RESET_HOOK is used to handle
+ * the PLTRST# vwire signal separate to the legacy power signal handling.
+ *
+ * Where !defined(CONFIG_AP_PWRSEQ) is used, the code is required either
+ * by the tests, or by the legacy power signal handling.
+ */
+
/* host command packet handler structure */
static struct host_packet lpc_packet;
/*
@@ -95,6 +114,7 @@ static enum espi_vwire_signal signal_to_zephyr_vwire(enum espi_vw_signal signal)
}
}
+#if defined(CONFIG_PLATFORM_EC_POWERSEQ)
/* Translate a Zephyr vwire to a platform/ec signal */
static enum espi_vw_signal zephyr_vwire_to_signal(enum espi_vwire_signal vwire)
{
@@ -105,6 +125,7 @@ static enum espi_vw_signal zephyr_vwire_to_signal(enum espi_vwire_signal vwire)
return -1;
}
}
+#endif /* defined(CONFIG_PLATFORM_EC_POWERSEQ) */
/*
* Bit field for each signal which can have an interrupt enabled.
@@ -126,22 +147,12 @@ static uint32_t signal_to_interrupt_bit(enum espi_vw_signal signal)
}
}
-/* 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);
- }
-}
-
#endif /* !defined(CONFIG_AP_PWRSEQ) */
#ifdef CONFIG_PLATFORM_EC_CHIPSET_RESET_HOOK
+/*
+ * Deferred handler for PLTRST processing.
+ */
static void espi_chipset_reset(void)
{
if (IS_ENABLED(CONFIG_AP_PWRSEQ)) {
@@ -151,16 +162,35 @@ static void espi_chipset_reset(void)
}
}
DECLARE_DEFERRED(espi_chipset_reset);
+#endif /* CONFIG_PLATFORM_EC_CHIPSET_RESET_HOOK */
-/* Callback for reset */
-static void espi_reset_handler(const struct device *dev,
+/*
+ * Callback for vwire received.
+ * PLTRST (platform reset) is handled specially by
+ * invoking HOOK_CHIPSET_RESET.
+ */
+#if defined(CONFIG_PLATFORM_EC_POWERSEQ) || \
+ defined(CONFIG_PLATFORM_EC_CHIPSET_RESET_HOOK)
+static void espi_vwire_handler(const struct device *dev,
struct espi_callback *cb,
struct espi_event event)
{
- hook_call_deferred(&espi_chipset_reset_data, MSEC);
+#if defined(CONFIG_PLATFORM_EC_POWERSEQ)
+ int ec_signal = zephyr_vwire_to_signal(event.evt_details);
+ if (signal_interrupt_enabled & signal_to_interrupt_bit(ec_signal)) {
+ power_signal_interrupt(ec_signal);
+ }
+#endif
+#if defined(CONFIG_PLATFORM_EC_CHIPSET_RESET_HOOK)
+ /* If PLTRST# asserted (low) then send reset hook */
+ if (event.evt_details == ESPI_VWIRE_SIGNAL_PLTRST &&
+ event.evt_data == 0) {
+ hook_call_deferred(&espi_chipset_reset_data, MSEC);
+ }
+#endif
}
-#endif /* CONFIG_PLATFORM_EC_CHIPSET_RESET_HOOK */
+#endif
#define espi_dev DEVICE_DT_GET(DT_CHOSEN(cros_ec_espi))
@@ -289,46 +319,76 @@ void lpc_update_host_event_status(void)
uint32_t status;
int need_sci = 0;
int need_smi = 0;
+ int rv;
if (!init_done)
return;
/* Disable PMC1 interrupt while updating status register */
enable = 0;
- espi_write_lpc_request(espi_dev, ECUSTOM_HOST_SUBS_INTERRUPT_EN,
- &enable);
-
- espi_read_lpc_request(espi_dev, EACPI_READ_STS, &status);
- if (lpc_get_host_events_by_type(LPC_HOST_EVENT_SMI)) {
- /* Only generate SMI for first event */
- if (!(status & EC_LPC_STATUS_SMI_PENDING))
- need_smi = 1;
+ rv = espi_write_lpc_request(espi_dev, ECUSTOM_HOST_SUBS_INTERRUPT_EN,
+ &enable);
+ if (rv) {
+ LOG_ERR("ESPI write failed: "
+ "ECUSTOM_HOST_SUBS_INTERRUPT_EN = %d",
+ rv);
+ return;
+ }
- status |= EC_LPC_STATUS_SMI_PENDING;
- espi_write_lpc_request(espi_dev, EACPI_WRITE_STS, &status);
+ rv = espi_read_lpc_request(espi_dev, EACPI_READ_STS, &status);
+ if (rv) {
+ LOG_ERR("ESPI read failed: EACPI_READ_STS = %d", rv);
} else {
- status &= ~EC_LPC_STATUS_SMI_PENDING;
- espi_write_lpc_request(espi_dev, EACPI_WRITE_STS, &status);
+ if (lpc_get_host_events_by_type(LPC_HOST_EVENT_SMI)) {
+ /* Only generate SMI for first event */
+ if (!(status & EC_LPC_STATUS_SMI_PENDING))
+ need_smi = 1;
+
+ status |= EC_LPC_STATUS_SMI_PENDING;
+ rv = espi_write_lpc_request(espi_dev, EACPI_WRITE_STS,
+ &status);
+ } else {
+ status &= ~EC_LPC_STATUS_SMI_PENDING;
+ rv = espi_write_lpc_request(espi_dev, EACPI_WRITE_STS,
+ &status);
+ }
+ if (rv) {
+ LOG_ERR("ESPI write failed: EACPI_WRITE_STS = %d", rv);
+ }
}
- espi_read_lpc_request(espi_dev, EACPI_READ_STS, &status);
- if (lpc_get_host_events_by_type(LPC_HOST_EVENT_SCI)) {
- /* Generate SCI for every event */
- need_sci = 1;
-
- status |= EC_LPC_STATUS_SCI_PENDING;
- espi_write_lpc_request(espi_dev, EACPI_WRITE_STS, &status);
+ rv = espi_read_lpc_request(espi_dev, EACPI_READ_STS, &status);
+ if (rv) {
+ LOG_ERR("ESPI read failed: EACPI_READ_STS = %d", rv);
} else {
- status &= ~EC_LPC_STATUS_SCI_PENDING;
- espi_write_lpc_request(espi_dev, EACPI_WRITE_STS, &status);
+ if (lpc_get_host_events_by_type(LPC_HOST_EVENT_SCI)) {
+ /* Generate SCI for every event */
+ need_sci = 1;
+
+ status |= EC_LPC_STATUS_SCI_PENDING;
+ rv = espi_write_lpc_request(espi_dev, EACPI_WRITE_STS,
+ &status);
+ } else {
+ status &= ~EC_LPC_STATUS_SCI_PENDING;
+ rv = espi_write_lpc_request(espi_dev, EACPI_WRITE_STS,
+ &status);
+ }
+ if (rv) {
+ LOG_ERR("ESPI write failed: EACPI_WRITE_STS = %d", rv);
+ }
}
*(host_event_t *)host_get_memmap(EC_MEMMAP_HOST_EVENTS) =
lpc_get_host_events();
enable = 1;
- espi_write_lpc_request(espi_dev, ECUSTOM_HOST_SUBS_INTERRUPT_EN,
- &enable);
+ rv = espi_write_lpc_request(espi_dev, ECUSTOM_HOST_SUBS_INTERRUPT_EN,
+ &enable);
+ if (rv) {
+ LOG_ERR("ESPI write failed: "
+ "ECUSTOM_HOST_SUBS_INTERRUPT_EN = %d",
+ rv);
+ }
/* Process the wake events. */
lpc_update_wake(lpc_get_host_events_by_type(LPC_HOST_EVENT_WAKE));
@@ -362,19 +422,30 @@ static void handle_acpi_write(uint32_t data)
uint8_t value, result;
uint8_t is_cmd = is_acpi_command(data);
uint32_t status;
+ int rv;
value = get_acpi_value(data);
/* Handle whatever this was. */
if (acpi_ap_to_ec(is_cmd, value, &result)) {
data = result;
- espi_write_lpc_request(espi_dev, EACPI_WRITE_CHAR, &data);
+ rv = espi_write_lpc_request(espi_dev, EACPI_WRITE_CHAR, &data);
+ if (rv) {
+ LOG_ERR("ESPI write failed: EACPI_WRITE_CHAR = %d", rv);
+ }
}
/* Clear processing flag */
- espi_read_lpc_request(espi_dev, EACPI_READ_STS, &status);
- status &= ~EC_LPC_STATUS_PROCESSING;
- espi_write_lpc_request(espi_dev, EACPI_WRITE_STS, &status);
+ rv = espi_read_lpc_request(espi_dev, EACPI_READ_STS, &status);
+ if (rv) {
+ LOG_ERR("ESPI read failed: EACPI_READ_STS = %d", rv);
+ } else {
+ status &= ~EC_LPC_STATUS_PROCESSING;
+ rv = espi_write_lpc_request(espi_dev, EACPI_WRITE_STS, &status);
+ if (rv) {
+ LOG_ERR("ESPI write failed: EACPI_WRITE_STS = %d", rv);
+ }
+ }
/*
* ACPI 5.0-12.6.1: Generate SCI for Input Buffer Empty / Output Buffer
@@ -386,17 +457,24 @@ static void handle_acpi_write(uint32_t data)
static void lpc_send_response_packet(struct host_packet *pkt)
{
uint32_t data;
+ int rv;
/* TODO(b/176523211): check whether add EC_RES_IN_PROGRESS handle */
/* Write result to the data byte. This sets the TOH status bit. */
data = pkt->driver_result;
- espi_write_lpc_request(espi_dev, ECUSTOM_HOST_CMD_SEND_RESULT, &data);
+ rv = espi_write_lpc_request(espi_dev, ECUSTOM_HOST_CMD_SEND_RESULT,
+ &data);
+ if (rv) {
+ LOG_ERR("ESPI write failed: ECUSTOM_HOST_CMD_SEND_RESULT = %d",
+ rv);
+ }
}
static void handle_host_write(uint32_t data)
{
uint32_t shm_mem_host_cmd;
+ int rv;
if (EC_COMMAND_PROTOCOL_3 != (data & 0xff)) {
LOG_ERR("Don't support this version of the host command");
@@ -404,9 +482,12 @@ static void handle_host_write(uint32_t data)
return;
}
- espi_read_lpc_request(espi_dev, ECUSTOM_HOST_CMD_GET_PARAM_MEMORY,
- &shm_mem_host_cmd);
-
+ rv = espi_read_lpc_request(espi_dev, ECUSTOM_HOST_CMD_GET_PARAM_MEMORY,
+ &shm_mem_host_cmd);
+ if (rv) {
+ LOG_ERR("ESPI read failed: EACPI_READ_STS = %d", rv);
+ return;
+ }
lpc_packet.send_response = lpc_send_response_packet;
lpc_packet.request = (const void *)shm_mem_host_cmd;
@@ -428,17 +509,35 @@ static void handle_host_write(uint32_t data)
void lpc_set_acpi_status_mask(uint8_t mask)
{
uint32_t status;
- espi_read_lpc_request(espi_dev, EACPI_READ_STS, &status);
+ int rv;
+
+ rv = espi_read_lpc_request(espi_dev, EACPI_READ_STS, &status);
+ if (rv) {
+ LOG_ERR("ESPI read failed: EACPI_READ_STS = %d", rv);
+ return;
+ }
status |= mask;
- espi_write_lpc_request(espi_dev, EACPI_WRITE_STS, &status);
+ rv = espi_write_lpc_request(espi_dev, EACPI_WRITE_STS, &status);
+ if (rv) {
+ LOG_ERR("ESPI write failed: EACPI_WRITE_STS = %d", rv);
+ }
}
void lpc_clear_acpi_status_mask(uint8_t mask)
{
uint32_t status;
- espi_read_lpc_request(espi_dev, EACPI_READ_STS, &status);
+ int rv;
+
+ rv = espi_read_lpc_request(espi_dev, EACPI_READ_STS, &status);
+ if (rv) {
+ LOG_ERR("ESPI read failed: EACPI_READ_STS = %d", rv);
+ return;
+ }
status &= ~mask;
- espi_write_lpc_request(espi_dev, EACPI_WRITE_STS, &status);
+ rv = espi_write_lpc_request(espi_dev, EACPI_WRITE_STS, &status);
+ if (rv) {
+ LOG_ERR("ESPI write failed: EACPI_WRITE_STS = %d", rv);
+ }
}
/* Get protocol information */
@@ -463,27 +562,44 @@ DECLARE_HOST_COMMAND(EC_CMD_GET_PROTOCOL_INFO, lpc_get_protocol_info,
* This function is needed only for the obsolete platform which uses the GPIO
* for KBC's IRQ.
*/
-void lpc_keyboard_resume_irq(void) {}
+void lpc_keyboard_resume_irq(void)
+{
+}
void lpc_keyboard_clear_buffer(void)
{
+ int rv;
/* Clear OBF flag in host STATUS and HIKMST regs */
- espi_write_lpc_request(espi_dev, E8042_CLEAR_OBF, 0);
+ rv = espi_write_lpc_request(espi_dev, E8042_CLEAR_OBF, 0);
+ if (rv) {
+ LOG_ERR("ESPI write failed: E8042_CLEAR_OBF = %d", rv);
+ }
}
+
int lpc_keyboard_has_char(void)
{
uint32_t status;
+ int rv;
/* if OBF bit is '1', that mean still have a data in DBBOUT */
- espi_read_lpc_request(espi_dev, E8042_OBF_HAS_CHAR, &status);
+ rv = espi_read_lpc_request(espi_dev, E8042_OBF_HAS_CHAR, &status);
+ if (rv) {
+ LOG_ERR("ESPI read failed: E8042_OBF_HAS_CHAR = %d", rv);
+ return 0;
+ }
return status;
}
void lpc_keyboard_put_char(uint8_t chr, int send_irq)
{
uint32_t kb_char = chr;
+ int rv;
- espi_write_lpc_request(espi_dev, E8042_WRITE_KB_CHAR, &kb_char);
+ rv = espi_write_lpc_request(espi_dev, E8042_WRITE_KB_CHAR, &kb_char);
+ if (rv) {
+ LOG_ERR("ESPI write failed: E8042_WRITE_KB_CHAR = %d", rv);
+ return;
+ }
LOG_INF("KB put %02x", kb_char);
}
@@ -492,9 +608,16 @@ void lpc_aux_put_char(uint8_t chr, int send_irq)
{
uint32_t kb_char = chr;
uint32_t status = I8042_AUX_DATA;
+ int rv;
- espi_write_lpc_request(espi_dev, E8042_SET_FLAG, &status);
- espi_write_lpc_request(espi_dev, E8042_WRITE_KB_CHAR, &kb_char);
+ rv = espi_write_lpc_request(espi_dev, E8042_SET_FLAG, &status);
+ if (rv) {
+ LOG_ERR("ESPI write failed: E8042_SET_FLAG = %d", rv);
+ }
+ rv = espi_write_lpc_request(espi_dev, E8042_WRITE_KB_CHAR, &kb_char);
+ if (rv) {
+ LOG_ERR("ESPI write failed: E8042_WRITE_KB_CHAR = %d", rv);
+ }
LOG_INF("AUX put %02x", kb_char);
}
@@ -503,12 +626,16 @@ static void kbc_ibf_obe_handler(uint32_t data)
#ifdef HAS_TASK_KEYPROTO
uint8_t is_ibf = is_8042_ibf(data);
uint32_t status = I8042_AUX_DATA;
+ int rv;
if (is_ibf) {
- keyboard_host_write(get_8042_data(data),
- get_8042_type(data));
+ keyboard_host_write(get_8042_data(data), get_8042_type(data));
} else if (IS_ENABLED(CONFIG_8042_AUX)) {
- espi_write_lpc_request(espi_dev, E8042_CLEAR_FLAG, &status);
+ rv = espi_write_lpc_request(espi_dev, E8042_CLEAR_FLAG,
+ &status);
+ if (rv) {
+ LOG_ERR("ESPI write failed: E8042_CLEAR_FLAG = %d", rv);
+ }
}
task_wake(TASK_ID_KEYPROTO);
#endif
@@ -517,9 +644,14 @@ static void kbc_ibf_obe_handler(uint32_t data)
int lpc_keyboard_input_pending(void)
{
uint32_t status;
+ int rv;
/* if IBF bit is '1', that mean still have a data in DBBIN */
- espi_read_lpc_request(espi_dev, E8042_IBF_HAS_CHAR, &status);
+ rv = espi_read_lpc_request(espi_dev, E8042_IBF_HAS_CHAR, &status);
+ if (rv) {
+ LOG_ERR("ESPI read failed: E8042_IBF_HAS_CHAR = %d", rv);
+ return 0;
+ }
return status;
}
@@ -553,12 +685,12 @@ static void espi_peripheral_handler(const struct device *dev,
static int zephyr_shim_setup_espi(const struct device *unused)
{
- static struct {
- struct espi_callback cb;
+ static const struct {
espi_callback_handler_t handler;
enum espi_bus_event event_type;
} callbacks[] = {
-#if !defined(CONFIG_AP_PWRSEQ)
+#if defined(CONFIG_PLATFORM_EC_POWERSEQ) || \
+ defined(CONFIG_PLATFORM_EC_CHIPSET_RESET_HOOK)
{
.handler = espi_vwire_handler,
.event_type = ESPI_BUS_EVENT_VWIRE_RECEIVED,
@@ -568,13 +700,14 @@ static int zephyr_shim_setup_espi(const struct device *unused)
.handler = espi_peripheral_handler,
.event_type = ESPI_BUS_PERIPHERAL_NOTIFICATION,
},
-#ifdef CONFIG_PLATFORM_EC_CHIPSET_RESET_HOOK
+#if defined(CONFIG_AP_PWRSEQ) && DT_HAS_COMPAT_STATUS_OKAY(intel_ap_pwrseq_vw)
{
- .handler = espi_reset_handler,
- .event_type = ESPI_BUS_RESET,
+ .handler = power_signal_espi_cb,
+ .event_type = POWER_SIGNAL_ESPI_BUS_EVENTS,
},
#endif
};
+ static struct espi_callback cb[ARRAY_SIZE(callbacks)];
struct espi_cfg cfg = {
.io_caps = ESPI_IO_MODE_QUAD_LINES,
@@ -586,17 +719,17 @@ static int zephyr_shim_setup_espi(const struct device *unused)
if (!device_is_ready(espi_dev))
k_oops();
- /* 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,
+ espi_init_callback(&cb[i], callbacks[i].handler,
callbacks[i].event_type);
- espi_add_callback(espi_dev, &callbacks[i].cb);
+ espi_add_callback(espi_dev, &cb[i]);
+ }
+
+ /* Configure eSPI after callbacks are registered */
+ if (espi_config(espi_dev, &cfg)) {
+ LOG_ERR("Failed to configure eSPI device");
+ return -1;
}
return 0;