summaryrefslogtreecommitdiff
path: root/chip/npcx/espi.c
diff options
context:
space:
mode:
authorMulin Chao <mlchao@nuvoton.com>2016-08-04 11:20:45 +0800
committerchrome-bot <chrome-bot@chromium.org>2016-08-10 22:16:57 -0700
commitef6e93dc1bbf92821c9d3ff149f691fbdad1c015 (patch)
tree793e53f708df2537811314916ca00e43e269cb50 /chip/npcx/espi.c
parenta625b710c3e4d64a659ae20682b85dd552657b6c (diff)
downloadchrome-ec-ef6e93dc1bbf92821c9d3ff149f691fbdad1c015.tar.gz
npcx: Add espi driver of npcx5mng for x86-based platform.
Add espi driver for x86-based platform which support espi interface such as skylake and so on. Added source: 1. espi.c: Add drivers which supports the utilities of peripheral and virtual-wire channels so far. 2. espi.h: Add espi virtual-wire declaration for power sequence FW. Modified sources: 1. lpc.c: Add interrupts and initialization steps for espi. 2. gpio.c: Add interrupt handler of espi reset. BRANCH=none BUG=chrome-os-partner:34346 TEST=make buildall -j; test nuvoton IC specific drivers Change-Id: Ie80afe79d85aba47fc0b72898a8374c2898ec114 Signed-off-by: Mulin Chao <mlchao@nuvoton.com> Reviewed-on: https://chromium-review.googlesource.com/366181 Reviewed-by: Randall Spangler <rspangler@chromium.org>
Diffstat (limited to 'chip/npcx/espi.c')
-rw-r--r--chip/npcx/espi.c656
1 files changed, 656 insertions, 0 deletions
diff --git a/chip/npcx/espi.c b/chip/npcx/espi.c
new file mode 100644
index 0000000000..f998c7bb16
--- /dev/null
+++ b/chip/npcx/espi.c
@@ -0,0 +1,656 @@
+/* Copyright (c) 2016 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.
+ */
+
+/* ESPI module for Chrome EC */
+
+#include "registers.h"
+#include "system.h"
+#include "task.h"
+#include "console.h"
+#include "uart.h"
+#include "util.h"
+#include "power.h"
+#include "espi.h"
+#include "lpc_chip.h"
+
+/* Console output macros */
+#if !(DEBUG_ESPI)
+#define CPUTS(...)
+#define CPRINTS(...)
+#else
+#define CPUTS(outstr) cputs(CC_LPC, outstr)
+#define CPRINTS(format, args...) cprints(CC_LPC, format, ## args)
+#endif
+
+/* Default eSPI configuration for VW events */
+struct vwevms_config_t {
+ uint8_t idx; /* VW index */
+ uint8_t idx_en; /* Index enable */
+ uint8_t pltrst_en; /* Enable reset by PLTRST assert */
+ uint8_t espirst_en; /* Enable reset by eSPI_RST assert */
+ uint8_t int_en; /* Interrupt/Wake-up enable */
+};
+
+struct vwevsm_config_t {
+ uint8_t idx; /* VW index */
+ uint8_t idx_en; /* Index enable */
+ uint8_t pltrst_en; /* Enable reset by PLTRST assert */
+ uint8_t cdrst_en; /* Enable cold reset */
+ uint8_t valid; /* Valid VW mask */
+};
+
+/* Default MIWU configurations for VW events */
+struct host_wui_item {
+ uint16_t table : 2; /* MIWU table 0-2 */
+ uint16_t group : 3; /* MIWU group 0-7 */
+ uint16_t num : 3; /* MIWU bit 0-7 */
+ uint16_t edge : 4; /* MIWU edge trigger type rising/falling/any */
+};
+
+/* Mapping item between VW signal, index and value */
+struct vw_event_t {
+ uint16_t name; /* Name of signal */
+ uint8_t evt_idx; /* VW index of signal */
+ uint8_t evt_val; /* VW value of signal */
+};
+
+/* Default settings of VWEVMS registers (Please refer Table.43/44) */
+static const struct vwevms_config_t espi_in_list[] = {
+ /*IDX EN ENPL ENESP IE VW Event Bit 3 -0 (M->S) */
+ {0x02, 1, 0, 0, 0}, /* SLP_S3#, SLP_S4#, SLP_S5, Reserve */
+ {0x03, 1, 0, 1, 0}, /* SUS_STAT#, PLTRST#, ORST_WARN, Reserve */
+ {0x07, 1, 1, 1, 0}, /* HRST_WARN, SMIOUT#, NMIOUT#, Reserve */
+ {0x41, 1, 0, 1, 0}, /* SUS_WARN#, SPWRDN_ACK, Reserve, SLP_A# */
+ {0x42, 1, 0, 0, 0}, /* SLP_LAN#, SLP_WAN#, Reserve, Reserve */
+ {0x47, 1, 1, 1, 0}, /* HOST_C10, Reserve, Reserve, Reserve */
+};
+
+/* Default settings of VWEVSM registers (Please refer Table.43/44) */
+static const struct vwevsm_config_t espi_out_list[] = {
+ /*IDX EN ENPL ENCDR VDMASK VW Event Bit 3 -0 (S->M) */
+ {0x04, 1, 0, 0, 0x0D}, /* PME#, WAKE#, Reserve, ORST_ACK */
+ {0x05, 1, 0, 0, 0x0F}, /* SLV_BL_STS, ERR_NF, ERR_F, SLV_BL_DONE*/
+ {0x06, 1, 1, 0, 0x0C}, /* HRST_ACK, RCIN#, SMI#, SCI# */
+ {0x40, 1, 0, 0, 0x01}, /* Reserve, Reserve, Reserve, SUS_ACK# */
+};
+
+/* eSPI interrupts used in MIWU */
+static const struct host_wui_item espi_vw_int_list[] = {
+ /* ESPI_RESET */
+ {MIWU_TABLE_0, MIWU_GROUP_5, 5, MIWU_EDGE_RISING},
+ /* SLP_S3 */
+ {MIWU_TABLE_2, MIWU_GROUP_1, 0, MIWU_EDGE_ANYING},
+ /* SLP_S4 */
+ {MIWU_TABLE_2, MIWU_GROUP_1, 1, MIWU_EDGE_ANYING},
+ /* SLP_S5 */
+ {MIWU_TABLE_2, MIWU_GROUP_1, 2, MIWU_EDGE_ANYING},
+ /* VW_WIRE_PLTRST */
+ {MIWU_TABLE_2, MIWU_GROUP_1, 5, MIWU_EDGE_RISING},
+ /* VW_WIRE_OOB_RST_WARN */
+ {MIWU_TABLE_2, MIWU_GROUP_1, 6, MIWU_EDGE_ANYING},
+ /* VW_WIRE_HOST_RST_WARN */
+ {MIWU_TABLE_2, MIWU_GROUP_2, 0, MIWU_EDGE_ANYING},
+ /* VW_WIRE_SUS_WARN */
+ {MIWU_TABLE_2, MIWU_GROUP_2, 4, MIWU_EDGE_RISING},
+};
+
+/* VW signals used in eSPI */
+static const struct vw_event_t vw_events_list[] = {
+ {VW_SLP_S3_L, 0x02, 0x01}, /* index 02h (In) */
+ {VW_SLP_S4_L, 0x02, 0x02},
+ {VW_SLP_S5_L, 0x02, 0x04},
+ {VW_SUS_STAT_L, 0x03, 0x01}, /* index 03h (In) */
+ {VW_PLTRST_L, 0x03, 0x02},
+ {VW_OOB_RST_WARN, 0x03, 0x04},
+ {VW_OOB_RST_ACK, 0x04, 0x01}, /* index 04h (Out) */
+ {VW_WAKE_L, 0x04, 0x04},
+ {VW_PME_L, 0x04, 0x08},
+ {VW_ERROR_FATAL, 0x05, 0x02}, /* index 05h (Out) */
+ {VW_ERROR_NON_FATAL, 0x05, 0x04},
+ {VW_SLAVE_BTLD_STATUS_DONE, 0x05, 0x09},
+ {VW_SCI_L, 0x06, 0x01}, /* index 06h (Out) */
+ {VW_SMI_L, 0x06, 0x02},
+ {VW_RCIN_L, 0x06, 0x04},
+ {VW_HOST_RST_ACK, 0x06, 0x08},
+ {VW_HOST_RST_WARN, 0x07, 0x01}, /* index 07h (In) */
+ {VW_SUS_ACK, 0x40, 0x01}, /* index 40h (Out) */
+ {VW_SUS_WARN_L, 0x41, 0x01}, /* index 41h (In) */
+ {VW_SUS_PWRDN_ACK_L, 0x41, 0x02},
+ {VW_SLP_A_L, 0x41, 0x08},
+ {VW_SLP_LAN, 0x42, 0x01}, /* index 42h (In) */
+ {VW_SLP_WLAN, 0x42, 0x02},
+};
+
+/* Flag for SLAVE_BOOT_LOAD siganls */
+static uint8_t boot_load_done;
+
+/*****************************************************************************/
+/* eSPI internal utilities */
+
+/* Recovery utility for eSPI reset */
+static void espi_reset_recovery(void)
+{
+ /* TODO: Put recovery stuff related to eSPI reset here */
+
+ /* Clear boot load flag */
+ boot_load_done = 0;
+}
+
+/* Configure Master-to-Slave virtual wire inputs */
+static void espi_vw_config_in(const struct vwevms_config_t *config)
+{
+ uint32_t val;
+ uint8_t i, index;
+
+ switch (VM_TYPE(config->idx)) {
+ case ESPI_VW_TYPE_SYS_EV:
+ case ESPI_VW_TYPE_PLT:
+ for (i = 0; i < ESPI_VWEVMS_NUM; i++) {
+ index = VWEVMS_IDX_GET(NPCX_VWEVMS(i));
+ /* Set VW input register */
+ if (index == config->idx) {
+ /* Get Wire field */
+ val = NPCX_VWEVMS(i) & 0x0F;
+ val |= VWEVMS_FIELD(config->idx,
+ config->idx_en,
+ config->pltrst_en,
+ config->int_en,
+ config->espirst_en);
+ NPCX_VWEVMS(i) = val;
+ return;
+ }
+ }
+ CPRINTS("No match index of all VWEVMSs");
+ break;
+ default:
+ CPRINTS("No support type of VWEVMS");
+ break;
+ }
+}
+
+/* Configure Slave-to-Master virtual wire outputs */
+static void espi_vw_config_out(const struct vwevsm_config_t *config)
+{
+ uint32_t val;
+ uint8_t i, index;
+
+ switch (VM_TYPE(config->idx)) {
+ case ESPI_VW_TYPE_SYS_EV:
+ case ESPI_VW_TYPE_PLT:
+ for (i = 0; i < ESPI_VWEVSM_NUM; i++) {
+ index = VWEVSM_IDX_GET(NPCX_VWEVSM(i));
+ /* Set VW output register */
+ if (index == config->idx) {
+ /* Get Wire field */
+ val = NPCX_VWEVSM(i) & 0x0F;
+ val |= VWEVSM_FIELD(config->idx,
+ config->idx_en,
+ config->valid,
+ config->pltrst_en,
+ config->cdrst_en);
+ NPCX_VWEVSM(i) = val;
+ return;
+ }
+ }
+ CPRINTS("No match index of all VWEVSMs");
+ break;
+ default:
+ CPRINTS("No support type of VWEVSM");
+ break;
+ }
+}
+
+/* Config Master-to-Slave VWire interrupt edge type and enable it */
+static void espi_enable_vw_int(const struct host_wui_item *vwire_int)
+{
+ uint8_t table = vwire_int->table;
+ uint8_t group = vwire_int->group;
+ uint8_t num = vwire_int->num;
+ uint8_t edge = vwire_int->edge;
+
+ /* Set detection mode to edge */
+ CLEAR_BIT(NPCX_WKMOD(table, group), num);
+
+ if (edge != MIWU_EDGE_ANYING) {
+ /* Disable Any Edge */
+ CLEAR_BIT(NPCX_WKAEDG(table, group), num);
+ /* Enable Rising Edge */
+ if (edge == MIWU_EDGE_RISING)
+ CLEAR_BIT(NPCX_WKEDG(table, group), num);
+ /* Enable Falling Edge */
+ else
+ SET_BIT(NPCX_WKEDG(table, group), num);
+ } else
+ /* enable Any Edge */
+ SET_BIT(NPCX_WKAEDG(table, group), num);
+
+ /* Enable wake-up input sources */
+ SET_BIT(NPCX_WKEN(table, group), num);
+}
+
+/* Get vw index & value information by signal */
+static int espi_vw_get_signal_index(enum espi_vw_signal event)
+{
+ int index;
+
+ /* Find the vw index by signal name first */
+ for (index = 0; index < ARRAY_SIZE(vw_events_list); index++) {
+ if (vw_events_list[index].name == event)
+ break;
+ }
+ /* Cannot find the index */
+ if (index == ARRAY_SIZE(vw_events_list))
+ return -1;
+
+ return index;
+}
+
+/* The ISRs of VW signals which used for power sequences */
+void espi_vw_power_signal_interrupt(enum espi_vw_signal signal)
+{
+ /* TODO: Add VW handler in power/common.c */
+ power_signal_interrupt((enum gpio_signal) signal);
+}
+
+/*****************************************************************************/
+/* IC specific low-level driver */
+
+/**
+ * Set eSPI Virtual-Wire signal to Host
+ *
+ * @param signal vw signal needs to set
+ * @param level level of vw signal
+ * @return EC_SUCCESS, or non-zero if error.
+ */
+int espi_vw_set_wire(enum espi_vw_signal signal, uint8_t level)
+{
+ uint8_t offset, sig_idx, value;
+
+ /* Get index of vw signal list by signale name */
+ sig_idx = espi_vw_get_signal_index(signal);
+
+ /* Cannot find index by signal name */
+ if (sig_idx < 0)
+ return EC_ERROR_PARAM1;
+
+ /* Find the output register offset by vw index */
+ for (offset = 0; offset < ESPI_VWEVSM_NUM; offset++) {
+ uint8_t vw_idx = VWEVSM_IDX_GET(NPCX_VWEVSM(offset));
+ /* If index matches. break */
+ if (vw_idx == vw_events_list[sig_idx].evt_idx)
+ break;
+ }
+
+ /* Cannot match index */
+ if (offset == ESPI_VWEVSM_NUM)
+ return EC_ERROR_PARAM1;
+
+ value = GET_FIELD(NPCX_VWEVSM(offset), NPCX_VWEVSM_WIRE);
+ /* Set wire */
+ if (level)
+ value |= vw_events_list[sig_idx].evt_val;
+ else /* Clear wire */
+ value &= (~vw_events_list[sig_idx].evt_val);
+
+ SET_FIELD(NPCX_VWEVSM(offset), NPCX_VWEVSM_WIRE, value);
+
+ return EC_SUCCESS;
+}
+
+/**
+ * Get eSPI Virtual-Wire signal from host
+ *
+ * @param signal vw signal needs to get
+ * @return 1: set by host, otherwise: no signal
+ */
+int espi_vw_get_wire(enum espi_vw_signal signal)
+{
+ uint8_t offset, sig_idx, value;
+
+ /* Get index of vw signal list by signale name */
+ sig_idx = espi_vw_get_signal_index(signal);
+
+ /* Cannot find index by signal name */
+ if (sig_idx < 0)
+ return -1;
+
+ /* Find the input register offset by vw index */
+ for (offset = 0; offset < ESPI_VWEVMS_NUM; offset++) {
+ uint8_t vw_idx = VWEVMS_IDX_GET(NPCX_VWEVMS(offset));
+ /* If index matches. break */
+ if (vw_idx == vw_events_list[sig_idx].evt_idx)
+ break;
+ }
+
+ /* Cannot match index */
+ if (offset == ESPI_VWEVMS_NUM)
+ return -1;
+
+ /* Get wire & check with valid bits */
+ value = GET_FIELD(NPCX_VWEVMS(offset), NPCX_VWEVMS_WIRE);
+ value &= GET_FIELD(NPCX_VWEVMS(offset), NPCX_VWEVMS_VALID);
+
+ return !!(value & vw_events_list[sig_idx].evt_val);
+}
+
+/**
+ * Enable VW interrupt of power sequence signal
+ *
+ * @param signal vw signal needs to enable interrupt
+ * @return EC_SUCCESS, or non-zero if error.
+ */
+int espi_vw_enable_wire_int(enum espi_vw_signal signal)
+{
+ if (signal == VW_SLP_S3_L)
+ SET_BIT(NPCX_WKEN(MIWU_TABLE_2, MIWU_GROUP_1), 0);
+ else if (signal == VW_SLP_S4_L)
+ SET_BIT(NPCX_WKEN(MIWU_TABLE_2, MIWU_GROUP_1), 1);
+ else if (signal == VW_SLP_S5_L)
+ SET_BIT(NPCX_WKEN(MIWU_TABLE_2, MIWU_GROUP_1), 2);
+ else
+ return EC_ERROR_PARAM1;
+
+ return EC_SUCCESS;
+}
+
+/**
+ * Disable VW interrupt of power sequence signal
+ *
+ * @param signal vw signal needs to disable interrupt
+ * @return EC_SUCCESS, or non-zero if error.
+ */
+int espi_vw_disable_wire_int(enum espi_vw_signal signal)
+{
+ if (signal == VW_SLP_S3_L)
+ CLEAR_BIT(NPCX_WKEN(MIWU_TABLE_2, MIWU_GROUP_1), 0);
+ else if (signal == VW_SLP_S4_L)
+ CLEAR_BIT(NPCX_WKEN(MIWU_TABLE_2, MIWU_GROUP_1), 1);
+ else if (signal == VW_SLP_S5_L)
+ CLEAR_BIT(NPCX_WKEN(MIWU_TABLE_2, MIWU_GROUP_1), 2);
+ else
+ return EC_ERROR_PARAM1;
+
+ return EC_SUCCESS;
+}
+
+/*****************************************************************************/
+/* VW event handlers */
+
+/* PLTRST# event handler */
+void espi_vw_evt_pltrst(void)
+{
+ CPRINTS("VW PLTRST: %d", espi_vw_get_wire(VW_PLTRST_L));
+
+ /* Disable eSPI peripheral channel support first */
+ CLEAR_BIT(NPCX_ESPICFG, NPCX_ESPICFG_PCCHN_SUPP);
+
+ /* Enable eSPI peripheral channel */
+ SET_BIT(NPCX_ESPICFG, NPCX_ESPICFG_PCHANEN);
+ /* Initialize host settings */
+ host_register_init();
+
+ /* Re-enable eSPI peripheral channel support */
+ SET_BIT(NPCX_ESPICFG, NPCX_ESPICFG_PCCHN_SUPP);
+
+#ifdef CONFIG_CHIPSET_RESET_HOOK
+ if (lpc_get_pltrst_asserted()) {
+ /* Notify HOOK_CHIPSET_RESET */
+ hook_call_deferred(lpc_chipset_reset, MSEC);
+ }
+#endif
+}
+
+/* SLP_Sx event handler */
+void espi_vw_evt_slp_s3(void)
+{
+ CPRINTS("VW SLP_S3: %d", espi_vw_get_wire(VW_SLP_S3_L));
+ espi_vw_power_signal_interrupt(VW_SLP_S3_L);
+}
+
+void espi_vw_evt_slp_s4(void)
+{
+ CPRINTS("VW SLP_S4: %d", espi_vw_get_wire(VW_SLP_S4_L));
+ espi_vw_power_signal_interrupt(VW_SLP_S4_L);
+}
+
+void espi_vw_evt_slp_s5(void)
+{
+ CPRINTS("VW SLP_S5: %d", espi_vw_get_wire(VW_SLP_S5_L));
+ espi_vw_power_signal_interrupt(VW_SLP_S5_L);
+}
+
+/* OOB Reset event handler */
+void espi_vw_evt_oobrst(void)
+{
+ CPRINTS("VW OOB_RST: %d", espi_vw_get_wire(VW_OOB_RST_WARN));
+
+ /* Send ACK to host by WARN#'s wire */
+ espi_vw_set_wire(VW_OOB_RST_ACK, espi_vw_get_wire(VW_OOB_RST_WARN));
+}
+
+/* SUS_WARN# event handler */
+void espi_vw_evt_sus_warn(void)
+{
+ CPRINTS("VW SUS_WARN#: %d", espi_vw_get_wire(VW_SUS_WARN_L));
+
+ udelay(100);
+
+ /* Send ACK to host by WARN#'s wire */
+ espi_vw_set_wire(VW_SUS_ACK, espi_vw_get_wire(VW_SUS_WARN_L));
+}
+
+/* HOSTRST WARN event handler */
+void espi_vw_evt_hostrst_warn(void)
+{
+ CPRINTS("VW HOST_RST_WARN#: %d", espi_vw_get_wire(VW_HOST_RST_WARN));
+
+ /* Send ACK to host by WARN#'s wire */
+ espi_vw_set_wire(VW_HOST_RST_ACK, espi_vw_get_wire(VW_HOST_RST_WARN));
+}
+
+/*****************************************************************************/
+/* Interrupt handlers */
+
+/* eSPI reset assert/de-assert interrupt */
+void espi_espirst_handler(void)
+{
+ /* Clear pending bit of WUI */
+ SET_BIT(NPCX_WKPCL(MIWU_TABLE_0, MIWU_GROUP_5), 5);
+
+ CPRINTS("eSPI RST issued!");
+}
+
+/* Handle eSPI virtual wire interrupt 1 */
+void __espi_wk2a_interrupt(void)
+{
+ uint8_t pending_bits = NPCX_WKPND(MIWU_TABLE_2, MIWU_GROUP_1);
+
+ /* Clear pending bits of MIWU */
+ NPCX_WKPCL(MIWU_TABLE_2, MIWU_GROUP_1) = pending_bits;
+
+ /* Handle events of virtual-wire */
+ if (IS_BIT_SET(pending_bits, 0))
+ espi_vw_evt_slp_s3();
+ if (IS_BIT_SET(pending_bits, 1))
+ espi_vw_evt_slp_s4();
+ if (IS_BIT_SET(pending_bits, 2))
+ espi_vw_evt_slp_s5();
+ if (IS_BIT_SET(pending_bits, 5))
+ espi_vw_evt_pltrst();
+ if (IS_BIT_SET(pending_bits, 6))
+ espi_vw_evt_oobrst();
+}
+DECLARE_IRQ(NPCX_IRQ_WKINTA_2, __espi_wk2a_interrupt, 2);
+
+/* Handle eSPI virtual wire interrupt 2 */
+void __espi_wk2b_interrupt(void)
+{
+ uint8_t pending_bits = NPCX_WKPND(MIWU_TABLE_2, MIWU_GROUP_2);
+
+ /* Clear pending bits of MIWU */
+ NPCX_WKPCL(MIWU_TABLE_2, MIWU_GROUP_2) = pending_bits;
+
+ /* Handle events of virtual-wire */
+ if (IS_BIT_SET(pending_bits, 4))
+ espi_vw_evt_sus_warn();
+ if (IS_BIT_SET(pending_bits, 0))
+ espi_vw_evt_hostrst_warn();
+}
+DECLARE_IRQ(NPCX_IRQ_WKINTB_2, __espi_wk2b_interrupt, 2);
+
+/* Interrupt handler for eSPI status changed */
+void espi_interrupt(void)
+{
+ int chan;
+ uint32_t mask, status;
+
+ mask = NPCX_ESPIIE;
+ status = NPCX_ESPISTS & mask;
+
+ while (status) {
+ /* Clear pending bits first */
+ NPCX_ESPISTS = status;
+
+ if (IS_BIT_SET(status, NPCX_ESPISTS_BERR))
+ CPRINTS("eSPI Bus Error");
+
+ /* eSPI inband reset(from VW) */
+ if (IS_BIT_SET(status, NPCX_ESPISTS_IBRST)) {
+ CPRINTS("eSPI RST inband RST");
+ espi_reset_recovery();
+
+ } /* eSPI reset (from eSPI_rst pin) */
+ else if (IS_BIT_SET(status, NPCX_ESPISTS_ESPIRST)) {
+ CPRINTS("eSPI RST");
+ espi_reset_recovery();
+ }
+
+ /* eSPI configuration is updated */
+ if (IS_BIT_SET(status, NPCX_ESPISTS_CFGUPD)) {
+ /*
+ * If host enable/disable channel for VW/OOB/FLASH, EC
+ * should follow except Peripheral channel. It is
+ * handled by PLTRST separately.
+ */
+ for (chan = NPCX_ESPI_CH_VW; chan < NPCX_ESPI_CH_COUNT;
+ chan++) {
+ if (!IS_SLAVE_CHAN_ENABLE(chan) &&
+ IS_HOST_CHAN_EN(chan))
+ ENABLE_ESPI_CHAN(chan);
+ else if (IS_SLAVE_CHAN_ENABLE(chan) &&
+ !IS_HOST_CHAN_EN(chan))
+ DISABLE_ESPI_CHAN(chan);
+ }
+
+ /*
+ * Send SLAVE_BOOTLOAD_DONE and SLAVE_BOOTLOAD_STATUS
+ * events to host simultaneously. To indicate the
+ * completion of EC firmware code loading.
+ */
+ if (boot_load_done == 0 &&
+ IS_SLAVE_CHAN_ENABLE(NPCX_ESPI_CH_VW)) {
+
+ espi_vw_set_wire(VW_SLAVE_BTLD_STATUS_DONE, 1);
+ boot_load_done = 1;
+ }
+ }
+
+ /* Any VW signal sent by Host - leave it, handle in MIWU ISR */
+ if (IS_BIT_SET(status, NPCX_ESPISTS_VWUPD))
+ CPRINTS("VW Updated INT");
+
+ /* Get status again */
+ status = NPCX_ESPISTS & mask;
+ }
+}
+DECLARE_IRQ(NPCX_IRQ_ESPI, espi_interrupt, 3);
+
+/*****************************************************************************/
+/* eSPI Initialization functions */
+void espi_init(void)
+{
+ int i;
+
+ /* Support all channels */
+ NPCX_ESPICFG |= ESPI_SUPP_CH_ALL;
+
+ /* Support all I/O modes */
+ SET_FIELD(NPCX_ESPICFG, NPCX_ESPICFG_IOMODE_FILED,
+ NPCX_ESPI_IO_MODE_ALL);
+
+ /* Max freq 66 MHz of eSPI */
+ SET_FIELD(NPCX_ESPICFG, NPCX_ESPICFG_MAXFREQ_FILED,
+ NPCX_ESPI_MAXFREQ_66);
+
+ /* Configure Master-to-Slave Virtual Wire indexes (Inputs) */
+ for (i = 0; i < ARRAY_SIZE(espi_in_list); i++)
+ espi_vw_config_in(&espi_in_list[i]);
+
+ /* Configure Slave-to-Master Virtual Wire indexes (Outputs) */
+ for (i = 0; i < ARRAY_SIZE(espi_out_list); i++)
+ espi_vw_config_out(&espi_out_list[i]);
+
+ /* Configure MIWU for eSPI VW */
+ for (i = 0; i < ARRAY_SIZE(espi_vw_int_list); i++)
+ espi_enable_vw_int(&espi_vw_int_list[i]);
+}
+
+static int command_espi(int argc, char **argv)
+{
+ uint32_t chan;
+ char *e;
+
+ if (argc == 1) {
+ return EC_ERROR_INVAL;
+ /* Get value of eSPI registers */
+ } else if (argc == 2) {
+ int i;
+
+ if (strcasecmp(argv[1], "cfg") == 0) {
+ ccprintf("ESPICFG [0x%08x]\n", NPCX_ESPICFG);
+ } else if (strcasecmp(argv[1], "vsm") == 0) {
+ for (i = 0; i < ESPI_VWEVSM_NUM; i++) {
+ uint32_t val = NPCX_VWEVSM(i);
+ uint8_t idx = VWEVSM_IDX_GET(val);
+
+ ccprintf("VWEVSM%d: %02x [0x%08x]\n", i, idx,
+ val);
+ }
+ } else if (strcasecmp(argv[1], "vms") == 0) {
+ for (i = 0; i < ESPI_VWEVMS_NUM; i++) {
+ uint32_t val = NPCX_VWEVMS(i);
+ uint8_t idx = VWEVMS_IDX_GET(val);
+
+ ccprintf("VWEVMS%d: %02x [0x%08x]\n", i, idx,
+ val);
+ }
+ }
+ /* Enable/Disable the channels of eSPI */
+ } else if (argc == 3) {
+ uint32_t m = (uint32_t) strtoi(argv[2], &e, 0);
+
+ if (*e)
+ return EC_ERROR_PARAM2;
+ if (m < 0 || m > 4)
+ return EC_ERROR_PARAM2;
+ else if (m == 4)
+ chan = 0x0F;
+ else
+ chan = 0x01 << m;
+ if (strcasecmp(argv[1], "en") == 0)
+ NPCX_ESPICFG = NPCX_ESPICFG | chan;
+ else if (strcasecmp(argv[1], "dis") == 0)
+ NPCX_ESPICFG = NPCX_ESPICFG & ~chan;
+ else
+ return EC_ERROR_PARAM1;
+ ccprintf("ESPICFG [0x%08x]\n", NPCX_ESPICFG);
+ }
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(espi, command_espi,
+ "cfg/vms/vsm/en/dis [channel]",
+ "eSPI configurations",
+ NULL);
+