summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--zephyr/shim/src/espi.c134
1 files changed, 128 insertions, 6 deletions
diff --git a/zephyr/shim/src/espi.c b/zephyr/shim/src/espi.c
index 78bbd86bee..8f36e1ad50 100644
--- a/zephyr/shim/src/espi.c
+++ b/zephyr/shim/src/espi.c
@@ -14,13 +14,19 @@
#include "chipset.h"
#include "common.h"
#include "espi.h"
+#include "hooks.h"
#include "lpc.h"
#include "port80.h"
#include "power.h"
+#include "timer.h"
#include "zephyr_espi_shim.h"
+#define VWIRE_PULSE_TRIGGER_TIME 65
+
LOG_MODULE_REGISTER(espi_shim, CONFIG_ESPI_LOG_LEVEL);
+static bool init_done;
+
/*
* A mapping of platform/ec signals to Zephyr virtual wires.
*
@@ -181,7 +187,13 @@ int zephyr_shim_setup_espi(void)
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 ret = espi_send_vwire(espi_dev, signal_to_zephyr_vwire(signal),
+ level);
+
+ if (ret != 0)
+ LOG_ERR("Encountered error sending virtual wire signal");
+
+ return ret;
}
int espi_vw_get_wire(enum espi_vw_signal signal)
@@ -209,15 +221,125 @@ int espi_vw_disable_wire_int(enum espi_vw_signal signal)
return 0;
}
-static uint8_t lpc_memmap[256] __aligned(8);
-
uint8_t *lpc_get_memmap_range(void)
{
- /* TODO(b/175217186): implement eSPI functions for host commands */
- return lpc_memmap;
+ uint32_t lpc_memmap = 0;
+
+ if (espi_read_lpc_request(espi_dev, EACPI_GET_SHARED_MEMORY,
+ &lpc_memmap) != 0) {
+ LOG_ERR("Get lpc_memmap failed!\n");
+ }
+
+ return (uint8_t *)lpc_memmap;
+}
+
+/**
+ * Update the level-sensitive wake signal to the AP.
+ *
+ * @param wake_events Currently asserted wake events
+ */
+static void lpc_update_wake(host_event_t wake_events)
+{
+ /*
+ * Mask off power button event, since the AP gets that through a
+ * separate dedicated GPIO.
+ */
+ wake_events &= ~EC_HOST_EVENT_MASK(EC_HOST_EVENT_POWER_BUTTON);
+
+ /* Signal is asserted low when wake events is non-zero */
+ gpio_set_level(NAMED_GPIO(ec_pch_wake_odl), !wake_events);
+}
+
+static void lpc_generate_smi(void)
+{
+ /* Enforce signal-high for long enough to debounce high */
+ espi_vw_set_wire(VW_SMI_L, 1);
+ udelay(VWIRE_PULSE_TRIGGER_TIME);
+ espi_vw_set_wire(VW_SMI_L, 0);
+ udelay(VWIRE_PULSE_TRIGGER_TIME);
+ espi_vw_set_wire(VW_SMI_L, 1);
+}
+
+static void lpc_generate_sci(void)
+{
+ /* Enforce signal-high for long enough to debounce high */
+ espi_vw_set_wire(VW_SCI_L, 1);
+ udelay(VWIRE_PULSE_TRIGGER_TIME);
+ espi_vw_set_wire(VW_SCI_L, 0);
+ udelay(VWIRE_PULSE_TRIGGER_TIME);
+ espi_vw_set_wire(VW_SCI_L, 1);
}
void lpc_update_host_event_status(void)
{
- /* TODO(b/175217186): implement eSPI functions for host commands */
+ uint32_t enable;
+ uint32_t status;
+ int need_sci = 0;
+ int need_smi = 0;
+
+ 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;
+
+ status |= EC_LPC_STATUS_SMI_PENDING;
+ espi_write_lpc_request(espi_dev, EACPI_WRITE_STS, &status);
+ } else {
+ status &= ~EC_LPC_STATUS_SMI_PENDING;
+ espi_write_lpc_request(espi_dev, EACPI_WRITE_STS, &status);
+ }
+
+ 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);
+ } else {
+ status &= ~EC_LPC_STATUS_SCI_PENDING;
+ espi_write_lpc_request(espi_dev, EACPI_WRITE_STS, &status);
+ }
+
+ *(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);
+
+ /* Process the wake events. */
+ lpc_update_wake(lpc_get_host_events_by_type(LPC_HOST_EVENT_WAKE));
+
+ /* Send pulse on SMI signal if needed */
+ if (need_smi)
+ lpc_generate_smi();
+
+ /* ACPI 5.0-12.6.1: Generate SCI for SCI_EVT=1. */
+ if (need_sci)
+ lpc_generate_sci();
}
+
+static void host_command_init(void)
+{
+ /* We support LPC args and version 3 protocol */
+ *(lpc_get_memmap_range() + EC_MEMMAP_HOST_CMD_FLAGS) =
+ EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED |
+ EC_HOST_CMD_FLAG_VERSION_3;
+
+ /* Sufficiently initialized */
+ init_done = 1;
+
+ lpc_update_host_event_status();
+}
+
+DECLARE_HOOK(HOOK_INIT, host_command_init, HOOK_PRIO_INIT_LPC);