summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJun Lin <CHLin56@nuvoton.com>2021-03-26 17:29:16 +0800
committerCommit Bot <commit-bot@chromium.org>2021-03-31 15:22:58 +0000
commit6f75875da06461dd65f13e2741e16034d27b0289 (patch)
treeb01d31e859c9c04ee828b08e8d98262c9952351b
parentcf62c88b539f0ebc8935a8cf9c375002e7a9e33f (diff)
downloadchrome-ec-6f75875da06461dd65f13e2741e16034d27b0289.tar.gz
zephyr: npcx: support SHI driver
Add the support for SHI (Serial Host Interface) driver. This is used to transfer host commands between EC and ARM-based AP. BUG=b:182600858 BRANCH=none TEST=Test host command "version" and "Hello" on npcx7_evb and the host emulator. Signed-off-by: Jun Lin <CHLin56@nuvoton.com> Change-Id: I5f290fe910600162764f5728f094dd0f42d508ef Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2786887 Reviewed-by: Jack Rosenthal <jrosenth@chromium.org> Commit-Queue: Jack Rosenthal <jrosenth@chromium.org> Tested-by: Jack Rosenthal <jrosenth@chromium.org>
-rw-r--r--zephyr/drivers/CMakeLists.txt1
-rw-r--r--zephyr/drivers/Kconfig1
-rw-r--r--zephyr/drivers/cros_shi/CMakeLists.txt5
-rw-r--r--zephyr/drivers/cros_shi/Kconfig37
-rw-r--r--zephyr/drivers/cros_shi/cros_shi_npcx.c905
-rw-r--r--zephyr/dts/bindings/cros_shi/nuvoton,npcx-cros-shi.yaml35
-rw-r--r--zephyr/include/cros/nuvoton/npcx.dtsi13
-rw-r--r--zephyr/include/drivers/cros_shi.h89
-rw-r--r--zephyr/include/soc/nuvoton_npcx/reg_def_cros.h83
9 files changed, 1169 insertions, 0 deletions
diff --git a/zephyr/drivers/CMakeLists.txt b/zephyr/drivers/CMakeLists.txt
index 6ffa0465e2..5435ee6b84 100644
--- a/zephyr/drivers/CMakeLists.txt
+++ b/zephyr/drivers/CMakeLists.txt
@@ -6,4 +6,5 @@ add_subdirectory(cros_bbram)
add_subdirectory(cros_flash)
add_subdirectory(cros_kb_raw)
add_subdirectory(cros_rtc)
+add_subdirectory(cros_shi)
add_subdirectory(cros_system)
diff --git a/zephyr/drivers/Kconfig b/zephyr/drivers/Kconfig
index 0b579713cb..37cf390a64 100644
--- a/zephyr/drivers/Kconfig
+++ b/zephyr/drivers/Kconfig
@@ -7,3 +7,4 @@ rsource "cros_flash/Kconfig"
rsource "cros_kb_raw/Kconfig"
rsource "cros_rtc/Kconfig"
rsource "cros_system/Kconfig"
+rsource "cros_shi/Kconfig"
diff --git a/zephyr/drivers/cros_shi/CMakeLists.txt b/zephyr/drivers/cros_shi/CMakeLists.txt
new file mode 100644
index 0000000000..6bc531b185
--- /dev/null
+++ b/zephyr/drivers/cros_shi/CMakeLists.txt
@@ -0,0 +1,5 @@
+# Copyright 2021 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.
+
+zephyr_library_sources_ifdef(CONFIG_CROS_SHI_NPCX cros_shi_npcx.c)
diff --git a/zephyr/drivers/cros_shi/Kconfig b/zephyr/drivers/cros_shi/Kconfig
new file mode 100644
index 0000000000..1b1caf4896
--- /dev/null
+++ b/zephyr/drivers/cros_shi/Kconfig
@@ -0,0 +1,37 @@
+# Copyright 2021 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.
+
+menuconfig CROS_SHI_NPCX
+ bool "Nuvoton NPCX Serial Host Interface driver for the Zephyr shim"
+ depends on SOC_FAMILY_NPCX
+ default n
+ help
+ This option enables Serial Host Interface driver for the NPCX family
+ of processors. This is used for host-command communication on the
+ platform which AP is ARM-based SoC.
+
+if CROS_SHI_NPCX
+config CROS_SHI_MAX_REQUEST
+ hex "Max data size for the version 3 request packet"
+ default 0x220
+ help
+ This option indicates maximum data size for a version 3 request
+ packet. This must be big enough to handle a request header of host
+ command, flash write offset/size, and 512 bytes of flash data.
+
+config CROS_SHI_MAX_RESPONSE
+ hex "Max data size for the version 3 response packet"
+ default 0x220
+ help
+ This option indicates maximum data size for a version 3 response
+ packet. This must be big enough to handle a response header of host
+ command, flash read offset/size, and 512 bytes of flash data.
+
+config CROS_SHI_NPCX_DEBUG
+ bool "Enable SHI debug"
+ default n
+ help
+ print the debug messages for SHI module
+
+endif # CROS_SHI_NPCX
diff --git a/zephyr/drivers/cros_shi/cros_shi_npcx.c b/zephyr/drivers/cros_shi/cros_shi_npcx.c
new file mode 100644
index 0000000000..27ec8292aa
--- /dev/null
+++ b/zephyr/drivers/cros_shi/cros_shi_npcx.c
@@ -0,0 +1,905 @@
+/* Copyright 2021 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.
+ */
+
+#define DT_DRV_COMPAT nuvoton_npcx_cros_shi
+
+#include <arch/arm/aarch32/cortex_m/cmsis.h>
+#include <assert.h>
+#include <dt-bindings/clock/npcx_clock.h>
+#include <drivers/clock_control.h>
+#include <drivers/cros_shi.h>
+#include <drivers/gpio.h>
+#include <logging/log.h>
+#include <kernel.h>
+#include <soc.h>
+#include <soc/nuvoton_npcx/reg_def_cros.h>
+
+#include "host_command.h"
+#include "soc_miwu.h"
+#include "system.h"
+
+#ifdef CONFIG_CROS_SHI_NPCX_DEBUG
+#define DEBUG_CPRINTS(format, args...) cprints(CC_SPI, format, ##args)
+#define DEBUG_CPRINTF(format, args...) cprintf(CC_SPI, format, ##args)
+#else
+#define DEBUG_CPRINTS(...)
+#define DEBUG_CPRINTF(...)
+#endif
+
+LOG_MODULE_REGISTER(cros_shi, LOG_LEVEL_DBG);
+
+#define SHI_NODE DT_NODELABEL(shi)
+#define SHI_VER_CTRL_PH DT_PHANDLE_BY_IDX(SHI_NODE, ver_ctrl, 0)
+#define SHI_VER_CTRL_ALT_FILED(f) DT_PHA_BY_IDX(SHI_VER_CTRL_PH, alts, 0, f)
+
+/* Full output buffer size */
+#define SHI_OBUF_FULL_SIZE 128
+/* Full input buffer size */
+#define SHI_IBUF_FULL_SIZE 128
+/* Configure the IBUFLVL2 = the size of V3 protocol header */
+#define SHI_IBUFLVL2_THRESHOLD (sizeof(struct ec_host_request))
+/* Half output buffer size */
+#define SHI_OBUF_HALF_SIZE (SHI_OBUF_FULL_SIZE / 2)
+/* Half input buffer size */
+#define SHI_IBUF_HALF_SIZE (SHI_IBUF_FULL_SIZE / 2)
+
+/*
+ * Timeout to wait for SHI request packet
+ *
+ * This affects the slowest SPI clock we can support. A delay of 8192 us
+ * permits a 512-byte request at 500 KHz, assuming the master starts sending
+ * bytes as soon as it asserts chip select. That's as slow as we would
+ * practically want to run the SHI interface, since running it slower
+ * significantly impacts firmware update times.
+ */
+#define SHI_CMD_RX_TIMEOUT_US 8192
+
+/*
+ * The AP blindly clocks back bytes over the SPI interface looking for a
+ * framing byte. So this preamble must always precede the actual response
+ * packet.
+ */
+#define SHI_OUT_PREAMBLE_LENGTH 2
+
+/*
+ * Space allocation of the past-end status byte (EC_SPI_PAST_END) in the out_msg
+ * buffer.
+ */
+#define EC_SPI_PAST_END_LENGTH 1
+/*
+ * Space allocation of the frame status byte (EC_SPI_FRAME_START) in the out_msg
+ * buffer.
+ */
+#define EC_SPI_FRAME_START_LENGTH 1
+
+/*
+ * Offset of output parameters needs to account for pad and framing bytes and
+ * one last past-end byte at the end so any additional bytes clocked out by
+ * the AP will have a known and identifiable value.
+ */
+#define SHI_PROTO3_OVERHEAD (EC_SPI_PAST_END_LENGTH + EC_SPI_FRAME_START_LENGTH)
+
+/*
+ * Max data size for a version 3 request/response packet. This is big enough
+ * to handle a request/response header, flash write offset/size, and 512 bytes
+ * of flash data:
+ * sizeof(ec_host_request): 8
+ * sizeof(ec_params_flash_write): 8
+ * payload 512
+ */
+#define SHI_MAX_REQUEST_SIZE CONFIG_CROS_SHI_MAX_REQUEST
+#define SHI_MAX_RESPONSE_SIZE CONFIG_CROS_SHI_MAX_RESPONSE
+
+/*
+ * Our input and output msg buffers. These must be large enough for our largest
+ * message, including protocol overhead. The pointers after the protocol
+ * overhead, as passed to the host command handler, must be 32-bit aligned.
+ */
+#define SHI_OUT_START_PAD (4 * (EC_SPI_FRAME_START_LENGTH / 4 + 1))
+#define SHI_OUT_END_PAD (4 * (EC_SPI_PAST_END_LENGTH / 4 + 1))
+static uint8_t out_msg_padded[SHI_OUT_START_PAD + SHI_MAX_RESPONSE_SIZE +
+ SHI_OUT_END_PAD] __aligned(4);
+static uint8_t *const out_msg =
+ out_msg_padded + SHI_OUT_START_PAD - EC_SPI_FRAME_START_LENGTH;
+static uint8_t in_msg[SHI_MAX_REQUEST_SIZE] __aligned(4);
+
+/* Parameters used by host protocols */
+static struct host_packet shi_packet;
+
+enum cros_shi_npcx_state {
+ SHI_STATE_NONE = -1,
+ /* SHI not enabled (initial state, and when chipset is off) */
+ SHI_STATE_DISABLED = 0,
+ /* Ready to receive next request */
+ SHI_STATE_READY_TO_RECV,
+ /* Receiving request */
+ SHI_STATE_RECEIVING,
+ /* Processing request */
+ SHI_STATE_PROCESSING,
+ /* Canceling response since CS deasserted and output NOT_READY byte */
+ SHI_STATE_CNL_RESP_NOT_RDY,
+ /* Sending response */
+ SHI_STATE_SENDING,
+ /* Received data is invalid */
+ SHI_STATE_BAD_RECEIVED_DATA,
+};
+
+static enum cros_shi_npcx_state state;
+
+/* Device config */
+struct cros_shi_npcx_config {
+ /* Serial Host Interface (SHI) base address */
+ uintptr_t base;
+ /* clock configuration */
+ struct npcx_clk_cfg clk_cfg;
+ /* pinmux configuration */
+ const uint8_t alts_size;
+ const struct npcx_alt *alts_list;
+ /* SHI IRQ */
+ int irq;
+ struct npcx_wui shi_cs_wui;
+};
+
+/* SHI bus parameters */
+struct shi_bus_parameters {
+ uint8_t *rx_msg; /* Entry pointer of msg rx buffer */
+ uint8_t *tx_msg; /* Entry pointer of msg tx buffer */
+ volatile uint8_t *rx_buf; /* Entry pointer of receive buffer */
+ volatile uint8_t *tx_buf; /* Entry pointer of transmit buffer */
+ uint16_t sz_received; /* Size of received data in bytes */
+ uint16_t sz_sending; /* Size of sending data in bytes */
+ uint16_t sz_request; /* request bytes need to receive */
+ uint16_t sz_response; /* response bytes need to receive */
+ uint64_t rx_deadline; /* deadline of receiving */
+} shi_params;
+
+static const struct npcx_alt cros_shi_alts[] = NPCX_DT_ALT_ITEMS_LIST(0);
+
+static const struct cros_shi_npcx_config cros_shi_cfg = {
+ .base = DT_INST_REG_ADDR(0),
+ .clk_cfg = NPCX_DT_CLK_CFG_ITEM(0),
+ .alts_size = ARRAY_SIZE(cros_shi_alts),
+ .alts_list = cros_shi_alts,
+ .irq = DT_INST_IRQN(0),
+ .shi_cs_wui = NPCX_DT_WUI_ITEM_BY_NAME(0, shi_cs_wui),
+};
+
+struct cros_shi_npcx_data {
+ struct host_packet shi_packet;
+ sys_slist_t callbacks;
+};
+
+/* Driver convenience defines */
+#define DRV_CONFIG(dev) ((const struct cros_shi_npcx_config *)(dev)->config)
+#define DRV_DATA(dev) ((struct cros_shi_npcx_data *)(dev)->data)
+#define HAL_INSTANCE(dev) (struct shi_reg *)(DRV_CONFIG(dev)->base)
+
+/* Forward declaration */
+static void cros_shi_npcx_reset_prepare(struct shi_reg *const inst);
+
+/* Read pointer of input or output buffer by consecutive reading */
+static uint32_t shi_read_buf_pointer(struct shi_reg *const inst)
+{
+ uint8_t stat;
+
+ /* Wait for two consecutive equal values are read */
+ do {
+ stat = inst->IBUFSTAT;
+ } while (stat != inst->IBUFSTAT);
+
+ return (uint32_t)stat;
+}
+
+/*
+ * Valid offset of SHI output buffer to write.
+ * When SIMUL bit is set, IBUFPTR can be used instead of OBUFPTR
+ */
+static uint32_t shi_valid_obuf_offset(struct shi_reg *const inst)
+{
+ return (shi_read_buf_pointer(inst) + SHI_OUT_PREAMBLE_LENGTH) %
+ SHI_OBUF_FULL_SIZE;
+}
+
+/*
+ * This routine write SHI next half output buffer from msg buffer
+ */
+static void shi_write_half_outbuf(void)
+{
+ const uint32_t size =
+ MIN(SHI_OBUF_HALF_SIZE,
+ shi_params.sz_response - shi_params.sz_sending);
+ uint8_t *obuf_ptr = (uint8_t *)shi_params.tx_buf;
+ const uint8_t *obuf_end = obuf_ptr + size;
+ uint8_t *msg_ptr = shi_params.tx_msg;
+
+ /* Fill half output buffer */
+ while (obuf_ptr != obuf_end)
+ *obuf_ptr++ = *msg_ptr++;
+
+ shi_params.sz_sending += size;
+ shi_params.tx_buf = obuf_ptr;
+ shi_params.tx_msg = msg_ptr;
+}
+
+/*
+ * This routine read SHI input buffer to msg buffer until
+ * we have received a certain number of bytes
+ */
+static int shi_read_inbuf_wait(struct shi_reg *const inst, uint32_t szbytes)
+{
+ /* Copy data to msg buffer from input buffer */
+ for (uint32_t i = 0; i < szbytes; i++, shi_params.sz_received++) {
+ /*
+ * If input buffer pointer equals pointer which wants to read,
+ * it means data is not ready.
+ */
+ while (shi_params.rx_buf ==
+ inst->IBUF + shi_read_buf_pointer(inst)) {
+ if (k_uptime_get() > shi_params.rx_deadline) {
+ return 0;
+ }
+ }
+ /* Restore data to msg buffer */
+ *shi_params.rx_msg++ = *shi_params.rx_buf++;
+ }
+ return 1;
+}
+
+/* This routine fills out all SHI output buffer with status byte */
+static void shi_fill_out_status(struct shi_reg *const inst, uint8_t status)
+{
+ uint8_t start, end;
+ volatile uint8_t *fill_ptr;
+ volatile uint8_t *fill_end;
+ volatile uint8_t *obuf_end;
+ int key;
+
+ /* Disable interrupts in case the interfere by the other interrupts */
+ key = irq_lock();
+
+ /*
+ * Fill out output buffer with status byte and leave a gap for PREAMBLE.
+ * The gap guarantees the synchronization. The critical section should
+ * be done within this gap. No racing happens.
+ */
+ start = shi_valid_obuf_offset(inst);
+ end = (start + SHI_OBUF_FULL_SIZE - SHI_OUT_PREAMBLE_LENGTH) %
+ SHI_OBUF_FULL_SIZE;
+
+ fill_ptr = inst->OBUF + start;
+ fill_end = inst->OBUF + end;
+ obuf_end = inst->OBUF + SHI_OBUF_FULL_SIZE;
+ while (fill_ptr != fill_end) {
+ *fill_ptr++ = status;
+ if (fill_ptr == obuf_end)
+ fill_ptr = inst->OBUF;
+ }
+
+ /* End of critical section */
+ irq_unlock(key);
+}
+
+/* This routine handles shi received unexpected data */
+static void shi_bad_received_data(struct shi_reg *const inst)
+{
+ /* State machine mismatch, timeout, or protocol we can't handle. */
+ shi_fill_out_status(inst, EC_SPI_RX_BAD_DATA);
+ state = SHI_STATE_BAD_RECEIVED_DATA;
+
+ DEBUG_CPRINTF("BAD-");
+ DEBUG_CPRINTF("in_msg=[");
+ for (uint32_t i = 0; i < shi_params.sz_received; i++)
+ DEBUG_CPRINTF("%02x ", in_msg[i]);
+ DEBUG_CPRINTF("]\n");
+
+ /* Reset shi's state machine for error recovery */
+ cros_shi_npcx_reset_prepare(inst);
+
+ DEBUG_CPRINTF("END\n");
+}
+
+/*
+ * This routine write SHI output buffer from msg buffer over halt of it.
+ * It make sure we have enough time to handle next operations.
+ */
+static void shi_write_first_pkg_outbuf(struct shi_reg *const inst,
+ uint16_t szbytes)
+{
+ uint8_t size, offset;
+ volatile uint8_t *obuf_ptr;
+ volatile uint8_t *obuf_end;
+ uint8_t *msg_ptr;
+ uint32_t half_buf_remain; /* Remains in half buffer are free to write */
+
+ /* Start writing at our current OBUF position */
+ offset = shi_valid_obuf_offset(inst);
+ obuf_ptr = inst->OBUF + offset;
+ msg_ptr = shi_params.tx_msg;
+
+ /* Fill up to OBUF mid point, or OBUF end */
+ half_buf_remain = SHI_OBUF_HALF_SIZE - (offset % SHI_OBUF_HALF_SIZE);
+ size = MIN(half_buf_remain, szbytes - shi_params.sz_sending);
+ obuf_end = obuf_ptr + size;
+ while (obuf_ptr != obuf_end)
+ *obuf_ptr++ = *msg_ptr++;
+
+ /* Track bytes sent for later accounting */
+ shi_params.sz_sending += size;
+
+ /* Write data to beginning of OBUF if we've reached the end */
+ if (obuf_ptr == inst->OBUF + SHI_IBUF_FULL_SIZE)
+ obuf_ptr = inst->OBUF;
+
+ /* Fill next half output buffer */
+ size = MIN(SHI_OBUF_HALF_SIZE, szbytes - shi_params.sz_sending);
+ obuf_end = obuf_ptr + size;
+ while (obuf_ptr != obuf_end)
+ *obuf_ptr++ = *msg_ptr++;
+
+ /* Track bytes sent / last OBUF position written for later accounting */
+ shi_params.sz_sending += size;
+ shi_params.tx_buf = obuf_ptr;
+ shi_params.tx_msg = msg_ptr;
+}
+
+/**
+ * Called to send a response back to the host.
+ *
+ * Some commands can continue for a while. This function is called by
+ * host_command task after processing request is completed. It fills up the
+ * FIFOs with response package and the remaining data is handled in shi's ISR.
+ */
+static void shi_send_response_packet(struct host_packet *pkt)
+{
+ struct shi_reg *const inst = (struct shi_reg *)(cros_shi_cfg.base);
+ int key;
+
+ /*
+ * Disable interrupts. This routine is not called from interrupt
+ * context and buffer underrun will likely occur if it is
+ * preempted after writing its initial reply byte. Also, we must be
+ * sure our state doesn't unexpectedly change, in case we're expected
+ * to take RESP_NOT_RDY actions.
+ */
+ key = irq_lock();
+
+ if (state == SHI_STATE_PROCESSING) {
+ /* Append our past-end byte, which we reserved space for. */
+ ((uint8_t *)pkt->response)[pkt->response_size] =
+ EC_SPI_PAST_END;
+
+ /* Computing sending bytes of response */
+ shi_params.sz_response =
+ pkt->response_size + SHI_PROTO3_OVERHEAD;
+
+ /* Start to fill output buffer with msg buffer */
+ shi_write_first_pkg_outbuf(inst, shi_params.sz_response);
+ /* Transmit the reply */
+ state = SHI_STATE_SENDING;
+ DEBUG_CPRINTF("SND-");
+ } else if (state == SHI_STATE_CNL_RESP_NOT_RDY) {
+ /*
+ * If we're not processing, then the AP has already terminated
+ * the transaction, and won't be listening for a response.
+ * Reset state machine for next transaction.
+ */
+ cros_shi_npcx_reset_prepare(inst);
+ DEBUG_CPRINTF("END\n");
+ } else
+ DEBUG_CPRINTS("Unexpected state %d in response handler", state);
+
+ irq_unlock(key);
+}
+
+void shi_handle_host_package(struct shi_reg *const inst)
+{
+ uint32_t sz_inbuf_int = shi_params.sz_request / SHI_IBUF_HALF_SIZE;
+ uint32_t cnt_inbuf_int = shi_params.sz_received / SHI_IBUF_HALF_SIZE;
+
+ if (sz_inbuf_int - cnt_inbuf_int)
+ /* Need to receive data from buffer */
+ return;
+ uint32_t remain_bytes = shi_params.sz_request - shi_params.sz_received;
+
+ /* Read remaining bytes from input buffer */
+ if (!shi_read_inbuf_wait(inst, remain_bytes))
+ return shi_bad_received_data(inst);
+
+ /* Move to processing state */
+ state = SHI_STATE_PROCESSING;
+ DEBUG_CPRINTF("PRC-");
+
+ /* Fill output buffer to indicate we`re processing request */
+ shi_fill_out_status(inst, EC_SPI_PROCESSING);
+
+ /* Set up parameters for host request */
+ shi_packet.send_response = shi_send_response_packet;
+
+ shi_packet.request = in_msg;
+ shi_packet.request_temp = NULL;
+ shi_packet.request_max = sizeof(in_msg);
+ shi_packet.request_size = shi_params.sz_request;
+
+ /* Put FRAME_START in first byte */
+ out_msg[0] = EC_SPI_FRAME_START;
+ shi_packet.response = out_msg + EC_SPI_FRAME_START_LENGTH;
+
+ /* Reserve space for frame start and trailing past-end byte */
+ shi_packet.response_max = SHI_MAX_RESPONSE_SIZE;
+ shi_packet.response_size = 0;
+ shi_packet.driver_result = EC_RES_SUCCESS;
+
+ /* Go to common layer to handle request */
+ host_packet_receive(&shi_packet);
+}
+
+static void shi_parse_header(struct shi_reg *const inst)
+{
+ /* We're now inside a transaction */
+ state = SHI_STATE_RECEIVING;
+ DEBUG_CPRINTF("RV-");
+
+ /* Setup deadline time for receiving */
+ shi_params.rx_deadline = k_uptime_get() + SHI_CMD_RX_TIMEOUT_US;
+
+ /* Wait for version, command, length bytes */
+ if (!shi_read_inbuf_wait(inst, 3))
+ return shi_bad_received_data(inst);
+
+ if (in_msg[0] == EC_HOST_REQUEST_VERSION) {
+ /* Protocol version 3 */
+ struct ec_host_request *r = (struct ec_host_request *)in_msg;
+ int pkt_size;
+ /*
+ * If request is over half of input buffer,
+ * we need to modified the algorithm again.
+ */
+ __ASSERT_NO_MSG(sizeof(*r) < SHI_IBUF_HALF_SIZE);
+
+ /* Wait for the rest of the command header */
+ if (!shi_read_inbuf_wait(inst, sizeof(*r) - 3))
+ return shi_bad_received_data(inst);
+
+ /* Check how big the packet should be */
+ pkt_size = host_request_expected_size(r);
+ if (pkt_size == 0 || pkt_size > sizeof(in_msg))
+ return shi_bad_received_data(inst);
+
+ /* Computing total bytes need to receive */
+ shi_params.sz_request = pkt_size;
+
+ shi_handle_host_package(inst);
+ } else {
+ /* Invalid version number */
+ return shi_bad_received_data(inst);
+ }
+}
+
+static void shi_sec_ibf_int_enable(struct shi_reg *const inst, int enable)
+{
+ if (enable) {
+ /* Setup IBUFLVL2 threshold and enable it */
+ inst->SHICFG5 |= BIT(NPCX_SHICFG5_IBUFLVL2DIS);
+ SET_FIELD(inst->SHICFG5, NPCX_SHICFG5_IBUFLVL2,
+ SHI_IBUFLVL2_THRESHOLD);
+ inst->SHICFG5 &= ~BIT(NPCX_SHICFG5_IBUFLVL2DIS);
+ /* Enable IBHF2 event */
+ inst->EVENABLE2 |= BIT(NPCX_EVENABLE2_IBHF2EN);
+ } else {
+ /* Disable IBHF2 event first */
+ inst->EVENABLE2 &= ~BIT(NPCX_EVENABLE2_IBHF2EN);
+ /* Disable IBUFLVL2 and set threshold back to zero */
+ inst->SHICFG5 |= BIT(NPCX_SHICFG5_IBUFLVL2DIS);
+ SET_FIELD(inst->SHICFG5, NPCX_SHICFG5_IBUFLVL2, 0);
+ }
+}
+
+/* This routine copies SHI half input buffer data to msg buffer */
+static void shi_read_half_inbuf(void)
+{
+ /*
+ * Copy to read buffer until reaching middle/top address of
+ * input buffer or completing receiving data
+ */
+ do {
+ /* Restore data to msg buffer */
+ *shi_params.rx_msg++ = *shi_params.rx_buf++;
+ shi_params.sz_received++;
+ } while (shi_params.sz_received % SHI_IBUF_HALF_SIZE &&
+ shi_params.sz_received != shi_params.sz_request);
+}
+
+/*
+ * Avoid spamming the console with prints every IBF / IBHF interrupt, if
+ * we find ourselves in an unexpected state.
+ */
+static enum cros_shi_npcx_state last_error_state = SHI_STATE_NONE;
+
+static void log_unexpected_state(char *isr_name)
+{
+ if (state != last_error_state)
+ DEBUG_CPRINTF("Unexpected state %d in %s ISR", state, isr_name);
+ last_error_state = state;
+}
+
+static void shi_handle_cs_assert(struct shi_reg *const inst)
+{
+ /* If not enabled, ignore glitches on SHI_CS_L */
+ if (state == SHI_STATE_DISABLED)
+ return;
+
+ /* NOT_READY should be sent and there're no spi transaction now. */
+ if (state == SHI_STATE_CNL_RESP_NOT_RDY)
+ return;
+
+ /* Chip select is low = asserted */
+ if (state != SHI_STATE_READY_TO_RECV) {
+ /* State machine should be reset in EVSTAT_EOR ISR */
+ DEBUG_CPRINTF("Unexpected state %d in CS ISR", state);
+ return;
+ }
+
+ DEBUG_CPRINTF("CSL-");
+
+ /*
+ * Clear possible EOR event from previous transaction since it's
+ * irrelevant now that CS is re-asserted.
+ */
+ inst->EVSTAT = BIT(NPCX_EVSTAT_EOR);
+
+ /* Do not deep sleep during SHI transaction */
+ disable_sleep(SLEEP_MASK_SPI);
+}
+
+static void shi_handle_cs_deassert(struct shi_reg *const inst)
+{
+ /*
+ * If the buffer is still used by the host command.
+ * Change state machine for response handler.
+ */
+ if (state == SHI_STATE_PROCESSING) {
+ /*
+ * Mark not ready to prevent the other
+ * transaction immediately
+ */
+ shi_fill_out_status(inst, EC_SPI_NOT_READY);
+
+ state = SHI_STATE_CNL_RESP_NOT_RDY;
+
+ /*
+ * Disable SHI interrupt, it will remain disabled
+ * until shi_send_response_packet() is called and
+ * CS is asserted for a new transaction.
+ */
+ irq_disable(DT_INST_IRQN(0));
+
+ DEBUG_CPRINTF("CNL-");
+ return;
+ /* Next transaction but we're not ready */
+ } else if (state == SHI_STATE_CNL_RESP_NOT_RDY) {
+ return;
+ }
+
+ /* Error state for checking*/
+ if (state != SHI_STATE_SENDING) {
+ log_unexpected_state("CSNRE");
+ }
+ /* reset SHI and prepare to next transaction again */
+ cros_shi_npcx_reset_prepare(inst);
+ DEBUG_CPRINTF("END\n");
+}
+
+static void shi_handle_input_buf_half_full(struct shi_reg *const inst)
+{
+ if (state == SHI_STATE_RECEIVING) {
+ /* Read data from input to msg buffer */
+ shi_read_half_inbuf();
+ return shi_handle_host_package(inst);
+ } else if (state == SHI_STATE_SENDING) {
+ /* Write data from msg buffer to output buffer */
+ if (shi_params.tx_buf == inst->OBUF + SHI_OBUF_FULL_SIZE) {
+ /* Write data from bottom address again */
+ shi_params.tx_buf = inst->OBUF;
+ return shi_write_half_outbuf();
+ } else /* ignore it */
+ return;
+ } else if (state == SHI_STATE_PROCESSING) {
+ /* Wait for host to handle request */
+ } else {
+ /* Unexpected status */
+ log_unexpected_state("IBHF");
+ }
+}
+
+static void shi_handle_input_buf_full(struct shi_reg *const inst)
+{
+ if (state == SHI_STATE_RECEIVING) {
+ /* read data from input to msg buffer */
+ shi_read_half_inbuf();
+ /* Read to bottom address again */
+ shi_params.rx_buf = inst->IBUF;
+ return shi_handle_host_package(inst);
+ } else if (state == SHI_STATE_SENDING) {
+ /* Write data from msg buffer to output buffer */
+ if (shi_params.tx_buf == inst->OBUF + SHI_OBUF_HALF_SIZE)
+ return shi_write_half_outbuf();
+ else /* ignore it */
+ return;
+ } else if (state == SHI_STATE_PROCESSING) {
+ /* Wait for host to handle request */
+ return;
+ }
+ /* Unexpected status */
+ log_unexpected_state("IBF");
+}
+
+static void cros_shi_npcx_isr(const struct device *dev)
+{
+ uint8_t stat;
+ uint8_t stat2;
+ struct shi_reg *const inst = HAL_INSTANCE(dev);
+
+ /* Read status register and clear interrupt status early */
+ stat = inst->EVSTAT;
+ inst->EVSTAT = stat;
+ stat2 = inst->EVSTAT2;
+
+ /* SHI CS pin is asserted in EVSTAT2 */
+ if (IS_BIT_SET(stat2, NPCX_EVSTAT2_CSNFE)) {
+ /* Clear pending bit of CSNFE */
+ inst->EVSTAT2 = BIT(NPCX_EVSTAT2_CSNFE);
+ DEBUG_CPRINTF("CSNFE-");
+ /*
+ * BUSY bit is set when SHI_CS is asserted. If not, leave it for
+ * SHI_CS de-asserted event.
+ */
+ if (!IS_BIT_SET(inst->SHICFG2, NPCX_SHICFG2_BUSY)) {
+ DEBUG_CPRINTF("CSNB-");
+ return;
+ }
+ shi_handle_cs_assert(inst);
+ }
+
+ /*
+ * End of data for read/write transaction. i.e. SHI_CS is deasserted.
+ * Host completed or aborted transaction
+ *
+ * EOR has the limitation that it will not be set even if the SHI_CS is
+ * deasserted without SPI clocks. The new SHI module introduce the
+ * CSNRE bit which will be set when SHI_CS is deasserted regardless of
+ * SPI clocks.
+ */
+ if (IS_BIT_SET(stat2, NPCX_EVSTAT2_CSNRE)) {
+ /* Clear pending bit of CSNRE */
+ inst->EVSTAT2 = BIT(NPCX_EVSTAT2_CSNRE);
+ /*
+ * We're not in proper state.
+ * Mark not ready to abort next transaction
+ */
+ DEBUG_CPRINTF("CSH-");
+ return shi_handle_cs_deassert(inst);
+ }
+
+ /*
+ * The number of bytes received reaches the size of
+ * protocol V3 header(=8) after CS asserted.
+ */
+ if (IS_BIT_SET(stat2, NPCX_EVSTAT2_IBHF2)) {
+ /* Clear IBHF2 */
+ inst->EVSTAT2 = BIT(NPCX_EVSTAT2_IBHF2);
+ DEBUG_CPRINTF("HDR-");
+ /* Disable second IBF interrupt and start to parse header */
+ shi_sec_ibf_int_enable(inst, 0);
+ shi_parse_header(inst);
+ }
+
+ /*
+ * Indicate input/output buffer pointer reaches the half buffer size.
+ * Transaction is processing.
+ */
+ if (IS_BIT_SET(stat, NPCX_EVSTAT_IBHF)) {
+ return shi_handle_input_buf_half_full(inst);
+ }
+
+ /*
+ * Indicate input/output buffer pointer reaches the full buffer size.
+ * Transaction is processing.
+ */
+ if (IS_BIT_SET(stat, NPCX_EVSTAT_IBF)) {
+ return shi_handle_input_buf_full(inst);
+ }
+}
+
+static void cros_shi_npcx_reset_prepare(struct shi_reg *const inst)
+{
+ uint32_t i;
+
+ state = SHI_STATE_DISABLED;
+
+ irq_disable(DT_INST_IRQN(0));
+
+ /* Disable SHI unit to clear all status bits */
+ inst->SHICFG1 &= ~BIT(NPCX_SHICFG1_EN);
+
+ /* Initialize parameters of next transaction */
+ shi_params.rx_msg = in_msg;
+ shi_params.tx_msg = out_msg;
+ shi_params.rx_buf = inst->IBUF;
+ shi_params.tx_buf = inst->IBUF + SHI_OBUF_HALF_SIZE;
+ shi_params.sz_received = 0;
+ shi_params.sz_sending = 0;
+ shi_params.sz_request = 0;
+ shi_params.sz_response = 0;
+
+ /*
+ * Fill output buffer to indicate we`re
+ * ready to receive next transaction.
+ */
+ for (i = 1; i < SHI_OBUF_FULL_SIZE; i++)
+ inst->OBUF[i] = EC_SPI_RECEIVING;
+ inst->OBUF[0] = EC_SPI_OLD_READY;
+
+ /* SHI/Host Write/input buffer wrap-around enable */
+ inst->SHICFG1 = BIT(NPCX_SHICFG1_IWRAP) | BIT(NPCX_SHICFG1_WEN) |
+ BIT(NPCX_SHICFG1_EN);
+
+ state = SHI_STATE_READY_TO_RECV;
+ last_error_state = SHI_STATE_NONE;
+
+ shi_sec_ibf_int_enable(inst, 1);
+ irq_enable(DT_INST_IRQN(0));
+
+ /* Allow deep sleep at the end of SHI transaction */
+ enable_sleep(SLEEP_MASK_SPI);
+
+ DEBUG_CPRINTF("RDY-");
+}
+
+static int cros_shi_npcx_enable(const struct device *dev)
+{
+ const struct cros_shi_npcx_config *const config = DRV_CONFIG(dev);
+ struct shi_reg *const inst = HAL_INSTANCE(dev);
+
+ cros_shi_npcx_reset_prepare(inst);
+ npcx_miwu_irq_disable(&config->shi_cs_wui);
+
+ /* Configure pin-mux from GPIO to SHI. */
+ npcx_pinctrl_mux_configure(config->alts_list, config->alts_size, 1);
+
+ NVIC_ClearPendingIRQ(DT_INST_IRQN(0));
+ npcx_miwu_irq_enable(&config->shi_cs_wui);
+ irq_enable(DT_INST_IRQN(0));
+
+ return 0;
+}
+
+static int cros_shi_npcx_disable(const struct device *dev)
+{
+ const struct cros_shi_npcx_config *const config = DRV_CONFIG(dev);
+
+ state = SHI_STATE_DISABLED;
+
+ irq_disable(DT_INST_IRQN(0));
+ npcx_miwu_irq_disable(&config->shi_cs_wui);
+
+ /* Configure pin-mux from SHI to GPIO. */
+ npcx_pinctrl_mux_configure(config->alts_list, config->alts_size, 0);
+
+ return 0;
+
+ /*
+ * Allow deep sleep again in case CS dropped before ec was
+ * informed in hook function and turn off SHI's interrupt in time.
+ */
+ enable_sleep(SLEEP_MASK_SPI);
+}
+
+static int shi_npcx_init(const struct device *dev)
+{
+ int ret;
+ const struct cros_shi_npcx_config *const config = DRV_CONFIG(dev);
+ struct shi_reg *const inst = HAL_INSTANCE(dev);
+ const struct device *const clk_dev =
+ device_get_binding(NPCX_CLK_CTRL_NAME);
+ const struct npcx_alt shi_ver_ctrl[] = {
+ { .group = SHI_VER_CTRL_ALT_FILED(group),
+ .bit = SHI_VER_CTRL_ALT_FILED(bit),
+ .inverted = SHI_VER_CTRL_ALT_FILED(inv) }
+ };
+
+ /* Enable the new version of SHI hardware module. */
+ npcx_pinctrl_mux_configure(shi_ver_ctrl, 1, 1);
+
+ /* Turn on shi device clock first */
+ ret = clock_control_on(clk_dev,
+ (clock_control_subsys_t *)&config->clk_cfg);
+ if (ret < 0) {
+ DEBUG_CPRINTF("Turn on SHI clock fail %d", ret);
+ return ret;
+ }
+
+ /*
+ * TODO: for npcx9, HIF_TYP_SEL in DEVCNT register should be set
+ * by firmware because the BOOTER no longer touches it.
+ */
+
+ /*
+ * SHICFG1 (SHI Configuration 1) setting
+ * [7] - IWRAP = 1: Wrap input buffer to the first address
+ * [6] - CPOL = 0: Sampling on rising edge and output on falling edge
+ * [5] - DAS = 0: return STATUS reg data after Status command
+ * [4] - AUTOBE = 0: Automatically update the OBES bit in STATUS reg
+ * [3] - AUTIBF = 0: Automatically update the IBFS bit in STATUS reg
+ * [2] - WEN = 0: Enable host write to input buffer
+ * [1] - Reserved 0
+ * [0] - ENABLE = 0: Disable SHI at the beginning
+ */
+ inst->SHICFG1 = 0x80;
+
+ /*
+ * SHICFG2 (SHI Configuration 2) setting
+ * [7] - Reserved 0
+ * [6] - REEVEN = 0: Restart events are not used
+ * [5] - Reserved 0
+ * [4] - REEN = 0: Restart transactions are not used
+ * [3] - SLWU = 0: Seem-less wake-up is enabled by default
+ * [2] - ONESHOT= 0: WEN is cleared at the end of a write transaction
+ * [1] - BUSY = 0: SHI bus is busy 0: idle.
+ * [0] - SIMUL = 1: Turn on simultaneous Read/Write
+ */
+ inst->SHICFG2 = 0x01;
+
+ /*
+ * EVENABLE (Event Enable) setting
+ * [7] - IBOREN = 0: Input buffer overrun interrupt enable
+ * [6] - STSREN = 0: status read interrupt disable
+ * [5] - EOWEN = 0: End-of-Data for Write Transaction Interrupt Enable
+ * [4] - EOREN = 1: End-of-Data for Read Transaction Interrupt Enable
+ * [3] - IBHFEN = 1: Input Buffer Half Full Interrupt Enable
+ * [2] - IBFEN = 1: Input Buffer Full Interrupt Enable
+ * [1] - OBHEEN = 0: Output Buffer Half Empty Interrupt Enable
+ * [0] - OBEEN = 0: Output Buffer Empty Interrupt Enable
+ */
+ inst->EVENABLE = 0x1C;
+
+ /*
+ * EVENABLE2 (Event Enable 2) setting
+ * [2] - CSNFEEN = 1: SHI_CS Falling Edge Interrupt Enable
+ * [1] - CSNREEN = 1: SHI_CS Rising Edge Interrupt Enable
+ * [0] - IBHF2EN = 0: Input Buffer Half Full 2 Interrupt Enable
+ */
+ inst->EVENABLE2 = 0x06;
+
+ /* Clear SHI events status register */
+ inst->EVSTAT = 0xff;
+
+ npcx_miwu_interrupt_configure(&config->shi_cs_wui, NPCX_MIWU_MODE_EDGE,
+ NPCX_MIWU_TRIG_LOW);
+ /* SHI interrupt installation */
+ IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority),
+ cros_shi_npcx_isr, DEVICE_DT_INST_GET(0), 0);
+
+ return ret;
+}
+
+static const struct cros_shi_driver_api cros_shi_npcx_driver_api = {
+ .enable = cros_shi_npcx_enable,
+ .disable = cros_shi_npcx_disable,
+};
+
+static struct cros_shi_npcx_data cros_shi_data;
+DEVICE_DT_INST_DEFINE(0, shi_npcx_init, device_pm_control_nop, &cros_shi_data,
+ &cros_shi_cfg, PRE_KERNEL_1,
+ CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
+ &cros_shi_npcx_driver_api);
+
+/* KBS register structure check */
+NPCX_REG_SIZE_CHECK(shi_reg, 0x120);
+NPCX_REG_OFFSET_CHECK(shi_reg, SHICFG1, 0x001);
+NPCX_REG_OFFSET_CHECK(shi_reg, EVENABLE, 0x005);
+NPCX_REG_OFFSET_CHECK(shi_reg, IBUFSTAT, 0x00a);
+NPCX_REG_OFFSET_CHECK(shi_reg, EVENABLE2, 0x010);
+NPCX_REG_OFFSET_CHECK(shi_reg, OBUF, 0x020);
+NPCX_REG_OFFSET_CHECK(shi_reg, IBUF, 0x0A0);
diff --git a/zephyr/dts/bindings/cros_shi/nuvoton,npcx-cros-shi.yaml b/zephyr/dts/bindings/cros_shi/nuvoton,npcx-cros-shi.yaml
new file mode 100644
index 0000000000..cf54cde7f8
--- /dev/null
+++ b/zephyr/dts/bindings/cros_shi/nuvoton,npcx-cros-shi.yaml
@@ -0,0 +1,35 @@
+# Copyright (c) 2021 Google Inc.
+# SPDX-License-Identifier: Apache-2.0
+
+description: Nuvoton, NPCX Serial Host Interface (SHI) node
+
+compatible: "nuvoton,npcx-cros-shi"
+
+include: base.yaml
+
+properties:
+ reg:
+ description: mmio register space
+ required: true
+
+ clocks:
+ required: true
+ description: configurations of device source clock controller
+
+ pinctrl-0:
+ type: phandles
+ required: true
+ description: configurations of pinmux controllers
+
+ ver-ctrl:
+ type: phandle
+ required: true
+ description: configurations of SHI module version
+ shi-cs-wui:
+ type: phandle
+ required: true
+ description: |
+ Mapping table between Wake-Up Input (WUI) and SHI_CS signal.
+
+ For example the WUI mapping on NPCX7 would be
+ shi-cs-wui = <&wui_io53>;
diff --git a/zephyr/include/cros/nuvoton/npcx.dtsi b/zephyr/include/cros/nuvoton/npcx.dtsi
index 569995d775..9c646423bf 100644
--- a/zephyr/include/cros/nuvoton/npcx.dtsi
+++ b/zephyr/include/cros/nuvoton/npcx.dtsi
@@ -6,6 +6,8 @@
/dts-v1/;
+#include <nuvoton/npcx7m6fb.dtsi>
+
/ {
named-bbram-regions {
@@ -84,6 +86,17 @@
mtc_alarm = <&wui_mtc>;
label = "MTC";
};
+
+ shi: shi@4000f000 {
+ compatible = "nuvoton,npcx-cros-shi";
+ reg = <0x4000f000 0x120>;
+ interrupts = <18 2>;
+ clocks = <&pcc NPCX_CLOCK_BUS_APB3 NPCX_PWDWN_CTL5 1>;
+ pinctrl-0 = <&altc_shi_sl>;
+ ver-ctrl = <&altf_shi_new>;
+ shi-cs-wui =<&wui_io53>;
+ label = "SHI";
+ };
};
};
diff --git a/zephyr/include/drivers/cros_shi.h b/zephyr/include/drivers/cros_shi.h
new file mode 100644
index 0000000000..aab3507dd3
--- /dev/null
+++ b/zephyr/include/drivers/cros_shi.h
@@ -0,0 +1,89 @@
+/* Copyright 2021 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.
+ */
+
+/**
+ * @file
+ * @brief Chrome OS-specific API for Serial Host Interface (SHI)
+ */
+
+#ifndef ZEPHYR_INCLUDE_DRIVERS_CROS_SHI_H_
+#define ZEPHYR_INCLUDE_DRIVERS_CROS_SHI_H_
+
+/**
+ * @brief CROS Serial Host Interface Driver APIs
+ * @defgroup cros_shi_interface CROS Serial Host Interface Driver APIs
+ * @ingroup io_interfaces
+ * @{
+ */
+
+#include <kernel.h>
+#include <device.h>
+
+/**
+ * @cond INTERNAL_HIDDEN
+ *
+ * cros Serial Host Interface driver API definition and system call entry points
+ *
+ * (Internal use only.)
+ */
+typedef int (*cros_shi_api_enable)(const struct device *dev);
+
+typedef int (*cros_shi_api_disable)(const struct device *dev);
+
+/** @brief Driver API structure. */
+__subsystem struct cros_shi_driver_api {
+ cros_shi_api_enable enable;
+ cros_shi_api_disable disable;
+};
+
+/**
+ * @brief Enable SHI module.
+ *
+ * @param dev Pointer to the device structure for the driver instance.
+ *
+ * @retval non-negative if successful.
+ * @retval Negative errno code if failure.
+ */
+__syscall int cros_shi_enable(const struct device *dev);
+
+static inline int z_impl_cros_shi_enable(const struct device *dev)
+{
+ const struct cros_shi_driver_api *api =
+ (const struct cros_shi_driver_api *)dev->api;
+
+ if (!api->enable) {
+ return -ENOTSUP;
+ }
+
+ return api->enable(dev);
+}
+
+/**
+ * @brief Disable SHI module.
+ *
+ * @param dev Pointer to the device structure for the driver instance.
+ *
+ * @retval no return if successful.
+ * @retval Negative errno code if failure.
+ */
+__syscall int cros_shi_disable(const struct device *dev);
+
+static inline int z_impl_cros_shi_disable(const struct device *dev)
+{
+ const struct cros_shi_driver_api *api =
+ (const struct cros_shi_driver_api *)dev->api;
+
+ if (!api->disable) {
+ return -ENOTSUP;
+ }
+
+ return api->disable(dev);
+}
+
+/**
+ * @}
+ */
+#include <syscalls/cros_shi.h>
+#endif /* ZEPHYR_INCLUDE_DRIVERS_CROS_SHI_H_ */
diff --git a/zephyr/include/soc/nuvoton_npcx/reg_def_cros.h b/zephyr/include/soc/nuvoton_npcx/reg_def_cros.h
index 7b577bed32..8702502a13 100644
--- a/zephyr/include/soc/nuvoton_npcx/reg_def_cros.h
+++ b/zephyr/include/soc/nuvoton_npcx/reg_def_cros.h
@@ -165,4 +165,87 @@ struct mtc_reg {
#define NPCX_WTC_PTO 30
#define NPCX_WTC_WIE 31
+/* SHI (Serial Host Interface) registers */
+struct shi_reg {
+ volatile uint8_t reserved1;
+ /* 0x001: SHI Configuration 1 */
+ volatile uint8_t SHICFG1;
+ /* 0x002: SHI Configuration 2 */
+ volatile uint8_t SHICFG2;
+ volatile uint8_t reserved2[2];
+ /* 0x005: Event Enable */
+ volatile uint8_t EVENABLE;
+ /* 0x006: Event Status */
+ volatile uint8_t EVSTAT;
+ /* 0x007: SHI Capabilities */
+ volatile uint8_t CAPABILITY;
+ /* 0x008: Status */
+ volatile uint8_t STATUS;
+ volatile uint8_t reserved3;
+ /* 0x00A: Input Buffer Status */
+ volatile uint8_t IBUFSTAT;
+ /* 0x00B: Output Buffer Status */
+ volatile uint8_t OBUFSTAT;
+ /* 0x00C: SHI Configuration 3 */
+ volatile uint8_t SHICFG3;
+ /* 0x00D: SHI Configuration 4 */
+ volatile uint8_t SHICFG4;
+ /* 0x00E: SHI Configuration 5 */
+ volatile uint8_t SHICFG5;
+ /* 0x00F: Event Status 2 */
+ volatile uint8_t EVSTAT2;
+ /* 0x010: Event Enable 2 */
+ volatile uint8_t EVENABLE2;
+ volatile uint8_t reserved4[15];
+ /* 0x20~0x9F: Output Buffer */
+ volatile uint8_t OBUF[128];
+ /* 0xA0~0x11F: Input Buffer */
+ volatile uint8_t IBUF[128];
+};
+
+/* SHI register fields */
+#define NPCX_SHICFG1_EN 0
+#define NPCX_SHICFG1_MODE 1
+#define NPCX_SHICFG1_WEN 2
+#define NPCX_SHICFG1_AUTIBF 3
+#define NPCX_SHICFG1_AUTOBE 4
+#define NPCX_SHICFG1_DAS 5
+#define NPCX_SHICFG1_CPOL 6
+#define NPCX_SHICFG1_IWRAP 7
+#define NPCX_SHICFG2_SIMUL 0
+#define NPCX_SHICFG2_BUSY 1
+#define NPCX_SHICFG2_ONESHOT 2
+#define NPCX_SHICFG2_SLWU 3
+#define NPCX_SHICFG2_REEN 4
+#define NPCX_SHICFG2_RESTART 5
+#define NPCX_SHICFG2_REEVEN 6
+#define NPCX_EVENABLE_OBEEN 0
+#define NPCX_EVENABLE_OBHEEN 1
+#define NPCX_EVENABLE_IBFEN 2
+#define NPCX_EVENABLE_IBHFEN 3
+#define NPCX_EVENABLE_EOREN 4
+#define NPCX_EVENABLE_EOWEN 5
+#define NPCX_EVENABLE_STSREN 6
+#define NPCX_EVENABLE_IBOREN 7
+#define NPCX_EVSTAT_OBE 0
+#define NPCX_EVSTAT_OBHE 1
+#define NPCX_EVSTAT_IBF 2
+#define NPCX_EVSTAT_IBHF 3
+#define NPCX_EVSTAT_EOR 4
+#define NPCX_EVSTAT_EOW 5
+#define NPCX_EVSTAT_STSR 6
+#define NPCX_EVSTAT_IBOR 7
+#define NPCX_STATUS_OBES 6
+#define NPCX_STATUS_IBFS 7
+#define NPCX_SHICFG3_OBUFLVLDIS 7
+#define NPCX_SHICFG4_IBUFLVLDIS 7
+#define NPCX_SHICFG5_IBUFLVL2 FIELD(0, 6)
+#define NPCX_SHICFG5_IBUFLVL2DIS 7
+#define NPCX_EVSTAT2_IBHF2 0
+#define NPCX_EVSTAT2_CSNRE 1
+#define NPCX_EVSTAT2_CSNFE 2
+#define NPCX_EVENABLE2_IBHF2EN 0
+#define NPCX_EVENABLE2_CSNREEN 1
+#define NPCX_EVENABLE2_CSNFEEN 2
+
#endif /* _NUVOTON_NPCX_REG_DEF_CROS_H */