summaryrefslogtreecommitdiff
path: root/zephyr/shim/src/espi.c
diff options
context:
space:
mode:
authorJack Rosenthal <jrosenth@chromium.org>2021-11-04 12:11:58 -0600
committerCommit Bot <commit-bot@chromium.org>2021-11-05 04:22:34 +0000
commit252457d4b21f46889eebad61d4c0a65331919cec (patch)
tree01856c4d31d710b20e85a74c8d7b5836e35c3b98 /zephyr/shim/src/espi.c
parent08f5a1e6fc2c9467230444ac9b582dcf4d9f0068 (diff)
downloadchrome-ec-release-R98-14388.B-ish.tar.gz
In the interest of making long-term branch maintenance incur as little technical debt on us as possible, we should not maintain any files on the branch we are not actually using. This has the added effect of making it extremely clear when merging CLs from the main branch when changes have the possibility to affect us. The follow-on CL adds a convenience script to actually pull updates from the main branch and generate a CL for the update. BUG=b:204206272 BRANCH=ish TEST=make BOARD=arcada_ish && make BOARD=drallion_ish Signed-off-by: Jack Rosenthal <jrosenth@chromium.org> Change-Id: I17e4694c38219b5a0823e0a3e55a28d1348f4b18 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3262038 Reviewed-by: Jett Rink <jettrink@chromium.org> Reviewed-by: Tom Hughes <tomhughes@chromium.org>
Diffstat (limited to 'zephyr/shim/src/espi.c')
-rw-r--r--zephyr/shim/src/espi.c563
1 files changed, 0 insertions, 563 deletions
diff --git a/zephyr/shim/src/espi.c b/zephyr/shim/src/espi.c
deleted file mode 100644
index c064bd6157..0000000000
--- a/zephyr/shim/src/espi.c
+++ /dev/null
@@ -1,563 +0,0 @@
-/* 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 "acpi.h"
-#include "chipset.h"
-#include "common.h"
-#include "espi.h"
-#include "gpio.h"
-#include "hooks.h"
-#include "i8042_protocol.h"
-#include "keyboard_protocol.h"
-#include "lpc.h"
-#include "port80.h"
-#include "power.h"
-#include "task.h"
-#include "timer.h"
-#include "zephyr_espi_shim.h"
-
-#define VWIRE_PULSE_TRIGGER_TIME 65
-
-LOG_MODULE_REGISTER(espi_shim, CONFIG_ESPI_LOG_LEVEL);
-
-/* host command packet handler structure */
-static struct host_packet lpc_packet;
-/*
- * For the eSPI host command, request & response use the same share memory.
- * This is for input request temp buffer.
- */
-static uint8_t params_copy[EC_LPC_HOST_PACKET_SIZE] __aligned(4);
-static bool init_done;
-
-/*
- * 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_PERIPHERAL_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);
- }
-}
-
-#ifdef CONFIG_PLATFORM_EC_CHIPSET_RESET_HOOK
-static void espi_chipset_reset(void)
-{
- hook_notify(HOOK_CHIPSET_RESET);
-}
-DECLARE_DEFERRED(espi_chipset_reset);
-
-/* Callback for reset */
-static void espi_reset_handler(const struct device *dev,
- struct espi_callback *cb,
- struct espi_event event)
-{
- hook_call_deferred(&espi_chipset_reset_data, MSEC);
-
-}
-#endif /* CONFIG_PLATFORM_EC_CHIPSET_RESET_HOOK */
-
-#define ESPI_NODE DT_NODELABEL(espi0)
-static const struct device *espi_dev;
-
-
-int espi_vw_set_wire(enum espi_vw_signal signal, uint8_t 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)
-{
- 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;
-}
-
-uint8_t *lpc_get_memmap_range(void)
-{
- uint32_t lpc_memmap = 0;
- int result = espi_read_lpc_request(espi_dev, EACPI_GET_SHARED_MEMORY,
- &lpc_memmap);
-
- if (result != EC_SUCCESS)
- LOG_ERR("Get lpc_memmap failed (%d)!\n", result);
-
- 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(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)
-{
- 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);
-
-static void handle_acpi_write(uint32_t data)
-{
- uint8_t value, result;
- uint8_t is_cmd = is_acpi_command(data);
- uint32_t status;
-
- 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);
- }
-
- /* 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);
-
- /*
- * ACPI 5.0-12.6.1: Generate SCI for Input Buffer Empty / Output Buffer
- * Full condition on the kernel channel.
- */
- lpc_generate_sci();
-}
-
-static void lpc_send_response_packet(struct host_packet *pkt)
-{
- uint32_t data;
-
- /* 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);
-}
-
-static void handle_host_write(uint32_t data)
-{
- uint32_t shm_mem_host_cmd;
-
- if (EC_COMMAND_PROTOCOL_3 != (data & 0xff)) {
- LOG_ERR("Don't support this version of the host command");
- /* TODO:(b/175217186): error response for other versions */
- return;
- }
-
- espi_read_lpc_request(espi_dev, ECUSTOM_HOST_CMD_GET_PARAM_MEMORY,
- &shm_mem_host_cmd);
-
- lpc_packet.send_response = lpc_send_response_packet;
-
- lpc_packet.request = (const void *)shm_mem_host_cmd;
- lpc_packet.request_temp = params_copy;
- lpc_packet.request_max = sizeof(params_copy);
- /* Don't know the request size so pass in the entire buffer */
- lpc_packet.request_size = EC_LPC_HOST_PACKET_SIZE;
-
- lpc_packet.response = (void *)shm_mem_host_cmd;
- lpc_packet.response_max = EC_LPC_HOST_PACKET_SIZE;
- lpc_packet.response_size = 0;
-
- lpc_packet.driver_result = EC_RES_SUCCESS;
-
- host_packet_receive(&lpc_packet);
- return;
-}
-
-void lpc_set_acpi_status_mask(uint8_t mask)
-{
- uint32_t status;
- espi_read_lpc_request(espi_dev, EACPI_READ_STS, &status);
- status |= mask;
- espi_write_lpc_request(espi_dev, EACPI_WRITE_STS, &status);
-}
-
-void lpc_clear_acpi_status_mask(uint8_t mask)
-{
- uint32_t status;
- espi_read_lpc_request(espi_dev, EACPI_READ_STS, &status);
- status &= ~mask;
- espi_write_lpc_request(espi_dev, EACPI_WRITE_STS, &status);
-}
-
-/* Get protocol information */
-static enum ec_status lpc_get_protocol_info(struct host_cmd_handler_args *args)
-{
- struct ec_response_get_protocol_info *r = args->response;
-
- memset(r, 0, sizeof(*r));
- r->protocol_versions = BIT(3);
- r->max_request_packet_size = EC_LPC_HOST_PACKET_SIZE;
- r->max_response_packet_size = EC_LPC_HOST_PACKET_SIZE;
- r->flags = 0;
-
- args->response_size = sizeof(*r);
-
- return EC_RES_SUCCESS;
-}
-DECLARE_HOST_COMMAND(EC_CMD_GET_PROTOCOL_INFO, lpc_get_protocol_info,
- EC_VER_MASK(0));
-
-/*
- * 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_clear_buffer(void)
-{
- /* Clear OBF flag in host STATUS and HIKMST regs */
- espi_write_lpc_request(espi_dev, E8042_CLEAR_OBF, 0);
-}
-int lpc_keyboard_has_char(void)
-{
- uint32_t status;
-
- /* if OBF bit is '1', that mean still have a data in DBBOUT */
- espi_read_lpc_request(espi_dev, E8042_OBF_HAS_CHAR, &status);
- return status;
-}
-
-void lpc_keyboard_put_char(uint8_t chr, int send_irq)
-{
- uint32_t kb_char = chr;
-
- espi_write_lpc_request(espi_dev, E8042_WRITE_KB_CHAR, &kb_char);
- LOG_INF("KB put %02x", kb_char);
-}
-
-/* Put an aux char to host buffer by HIMDO and assert status bit 5. */
-void lpc_aux_put_char(uint8_t chr, int send_irq)
-{
- uint32_t kb_char = chr;
- uint32_t status = I8042_AUX_DATA;
-
- espi_write_lpc_request(espi_dev, E8042_SET_FLAG, &status);
- espi_write_lpc_request(espi_dev, E8042_WRITE_KB_CHAR, &kb_char);
- LOG_INF("AUX put %02x", kb_char);
-}
-
-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;
-
- if (is_ibf) {
- 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);
- }
- task_wake(TASK_ID_KEYPROTO);
-#endif
-}
-
-int lpc_keyboard_input_pending(void)
-{
- uint32_t status;
-
- /* if IBF bit is '1', that mean still have a data in DBBIN */
- espi_read_lpc_request(espi_dev, E8042_IBF_HAS_CHAR, &status);
- return status;
-}
-
-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);
- }
-
- if (IS_ENABLED(CONFIG_PLATFORM_EC_ACPI) &&
- event_type == ESPI_PERIPHERAL_HOST_IO) {
- handle_acpi_write(event.evt_data);
- }
-
- if (IS_ENABLED(CONFIG_PLATFORM_EC_HOSTCMD) &&
- event_type == ESPI_PERIPHERAL_EC_HOST_CMD) {
- handle_host_write(event.evt_data);
- }
-
- if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_8042_KBC) &&
- IS_ENABLED(HAS_TASK_KEYPROTO) &&
- event_type == ESPI_PERIPHERAL_8042_KBC) {
- kbc_ibf_obe_handler(event.evt_data);
- }
-}
-
-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,
- },
-#ifdef CONFIG_PLATFORM_EC_CHIPSET_RESET_HOOK
- {
- .handler = espi_reset_handler,
- .event_type = ESPI_BUS_RESET,
- },
-#endif
- };
-
- 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_DT_GET(ESPI_NODE);
- if (!device_is_ready(espi_dev)) {
- LOG_ERR("Error: device %s is not ready", espi_dev->name);
- 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;
-}