diff options
Diffstat (limited to 'zephyr/drivers/cros_shi')
-rw-r--r-- | zephyr/drivers/cros_shi/CMakeLists.txt | 6 | ||||
-rw-r--r-- | zephyr/drivers/cros_shi/Kconfig | 57 | ||||
-rw-r--r-- | zephyr/drivers/cros_shi/cros_shi_it8xxx2.c | 407 | ||||
-rw-r--r-- | zephyr/drivers/cros_shi/cros_shi_npcx.c | 899 |
4 files changed, 0 insertions, 1369 deletions
diff --git a/zephyr/drivers/cros_shi/CMakeLists.txt b/zephyr/drivers/cros_shi/CMakeLists.txt deleted file mode 100644 index f0b3c8bb5a..0000000000 --- a/zephyr/drivers/cros_shi/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -# 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_IT8XXX2 cros_shi_it8xxx2.c) -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 deleted file mode 100644 index 0baa8a5d80..0000000000 --- a/zephyr/drivers/cros_shi/Kconfig +++ /dev/null @@ -1,57 +0,0 @@ -# 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 - 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" - help - print the debug messages for SHI module - -endif # CROS_SHI_NPCX - -config CROS_SHI_IT8XXX2 - bool "ITE it81202 spi host interface driver for Zephyr" - depends on SOC_FAMILY_RISCV_ITE && AP_ARM - default y if PLATFORM_EC_HOSTCMD - help - This option enables spi host interface driver which is required to - communicate with the EC when the CPU is the ARM processor. - -if CROS_SHI_IT8XXX2 - -config CROS_SHI_IT8XXX2_INIT_PRIORITY - int "cros_shi it8xxx2 initialization priority" - default 52 - help - This sets the it8xxx2 cros_shi driver initialization priority. - In the GPIO shim, the alt function of SHI will be configured - as GPIO input pin. So the priority of cros_shi driver must be - lower than CONFIG_PLATFORM_EC_GPIO_INIT_PRIORITY, and - configuration these pins to alt function of SHI. - -endif # CROS_SHI_IT8XXX2 diff --git a/zephyr/drivers/cros_shi/cros_shi_it8xxx2.c b/zephyr/drivers/cros_shi/cros_shi_it8xxx2.c deleted file mode 100644 index 522d48ff09..0000000000 --- a/zephyr/drivers/cros_shi/cros_shi_it8xxx2.c +++ /dev/null @@ -1,407 +0,0 @@ -/* 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 ite_it8xxx2_cros_shi - -#include <device.h> -#include <errno.h> -#include <init.h> -#include <kernel.h> -#include <logging/log.h> -#include <soc.h> -#include <soc_dt.h> -#include <drivers/pinmux.h> -#include <dt-bindings/pinctrl/it8xxx2-pinctrl.h> - -#include "chipset.h" -#include "console.h" -#include "host_command.h" - -/* Console output macros */ -#define CPRINTS(format, args...) cprints(CC_SPI, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_SPI, format, ## args) - -LOG_MODULE_REGISTER(cros_shi, LOG_LEVEL_ERR); - -#define DRV_CONFIG(dev) ((struct cros_shi_it8xxx2_cfg * const)(dev)->config) - -/* - * Strcture cros_shi_it8xxx2_cfg is about the setting of SHI, - * this config will be used at initial time - */ -struct cros_shi_it8xxx2_cfg { - /* Pinmux control group */ - const struct device *pinctrls; - /* GPIO pin */ - uint8_t pin; - /* Alternate function */ - uint8_t alt_fun; -}; - -#define SPI_RX_MAX_FIFO_SIZE 256 -#define SPI_TX_MAX_FIFO_SIZE 256 - -#define EC_SPI_PREAMBLE_LENGTH 4 -#define EC_SPI_PAST_END_LENGTH 4 - -/* Max data size for a version 3 request/response packet. */ -#define SPI_MAX_REQUEST_SIZE SPI_RX_MAX_FIFO_SIZE -#define SPI_MAX_RESPONSE_SIZE (SPI_TX_MAX_FIFO_SIZE - \ - EC_SPI_PREAMBLE_LENGTH - EC_SPI_PAST_END_LENGTH) - -static const uint8_t out_preamble[EC_SPI_PREAMBLE_LENGTH] = { - EC_SPI_PROCESSING, - EC_SPI_PROCESSING, - EC_SPI_PROCESSING, - /* This is the byte which matters */ - EC_SPI_FRAME_START, -}; - -/* Store read and write data buffer */ -static uint8_t in_msg[SPI_RX_MAX_FIFO_SIZE] __aligned(4); -static uint8_t out_msg[SPI_TX_MAX_FIFO_SIZE] __aligned(4); - -/* Parameters used by host protocols */ -static struct host_packet spi_packet; - -enum shi_state_machine { - /* Ready to receive next request */ - SPI_STATE_READY_TO_RECV, - /* Receiving request */ - SPI_STATE_RECEIVING, - /* Processing request */ - SPI_STATE_PROCESSING, - /* Received bad data */ - SPI_STATE_RX_BAD, - - SPI_STATE_COUNT, -}; - -static enum shi_state_machine shi_state; - -static const int spi_response_state[] = { - [SPI_STATE_READY_TO_RECV] = EC_SPI_OLD_READY, - [SPI_STATE_RECEIVING] = EC_SPI_RECEIVING, - [SPI_STATE_PROCESSING] = EC_SPI_PROCESSING, - [SPI_STATE_RX_BAD] = EC_SPI_RX_BAD_DATA, -}; -BUILD_ASSERT(ARRAY_SIZE(spi_response_state) == SPI_STATE_COUNT); - -static void spi_set_state(int state) -{ - /* SPI slave state machine */ - shi_state = state; - /* Response spi slave state */ - IT83XX_SPI_SPISRDR = spi_response_state[state]; -} - -static void reset_rx_fifo(void) -{ - /* End Rx FIFO access */ - IT83XX_SPI_TXRXFAR = 0x00; - /* Rx FIFO reset and count monitor reset */ - IT83XX_SPI_FCR = IT83XX_SPI_RXFR | IT83XX_SPI_RXFCMR; -} - -/* This routine handles spi received unexcepted data */ -static void spi_bad_received_data(int count) -{ - /* State machine mismatch, timeout, or protocol we can't handle. */ - spi_set_state(SPI_STATE_RX_BAD); - /* End CPU access Rx FIFO, so it can clock in bytes from AP again. */ - IT83XX_SPI_TXRXFAR = 0; - - CPRINTS("SPI rx bad data"); - CPRINTF("in_msg=["); - for (int i = 0; i < count; i++) - CPRINTF("%02x ", in_msg[i]); - CPRINTF("]\n"); -} - -static void spi_response_host_data(uint8_t *out_msg_addr, int tx_size) -{ - /* - * Protect sequence of filling response packet for host. - * This will ensure CPU access FIFO is disabled at SPI end interrupt no - * matter the interrupt is triggered before or after the sequence. - */ - unsigned int key = irq_lock(); - - if (shi_state == SPI_STATE_PROCESSING) { - /* Tx FIFO reset and count monitor reset */ - IT83XX_SPI_TXFCR = IT83XX_SPI_TXFR | IT83XX_SPI_TXFCMR; - /* CPU Tx FIFO1 and FIFO2 access */ - IT83XX_SPI_TXRXFAR = IT83XX_SPI_CPUTFA; - - for (int i = 0; i < tx_size; i += 4) { - /* Write response data from out_msg buffer to Tx FIFO */ - IT83XX_SPI_CPUWTFDB0 = *(uint32_t *)(out_msg_addr + i); - } - - /* - * After writing data to Tx FIFO is finished, this bit will - * be to indicate the SPI slave controller. - */ - IT83XX_SPI_TXFCR = IT83XX_SPI_TXFS; - /* End Tx FIFO access */ - IT83XX_SPI_TXRXFAR = 0; - /* SPI slave read Tx FIFO */ - IT83XX_SPI_FCR = IT83XX_SPI_SPISRTXF; - } - - irq_unlock(key); -} - -/* - * Called to send a response back to the host. - * - * Some commands can continue for a while. This function is called by - * host_command when it completes. - * - */ -static void spi_send_response_packet(struct host_packet *pkt) -{ - int tx_size; - - if (shi_state != SPI_STATE_PROCESSING) { - CPRINTS("The request data is not processing."); - return; - } - - /* Append our past-end byte, which we reserved space for. */ - for (int i = 0; i < EC_SPI_PAST_END_LENGTH; i++) { - ((uint8_t *)pkt->response)[pkt->response_size + i] - = EC_SPI_PAST_END; - } - - tx_size = pkt->response_size + EC_SPI_PREAMBLE_LENGTH + - EC_SPI_PAST_END_LENGTH; - - /* Transmit the reply */ - spi_response_host_data(out_msg, tx_size); -} - -/* Store request data from Rx FIFO to in_msg buffer */ -static void spi_host_request_data(uint8_t *in_msg_addr, int count) -{ - /* CPU Rx FIFO1 access */ - IT83XX_SPI_TXRXFAR = IT83XX_SPI_CPURXF1A; - /* - * In spi_parse_header, the request data will separate to - * write in_msg buffer so we cannot set CPU to end accessing - * Rx FIFO in this function. We will set IT83XX_SPI_TXRXFAR = 0 - * in reset_rx_fifo. - */ - - for (int i = 0; i < count; i += 4) { - /* Get data from master to buffer */ - *(uint32_t *)(in_msg_addr + i) = IT83XX_SPI_RXFRDRB0; - } -} - -/* Parse header for version of spi-protocol */ -static void spi_parse_header(void) -{ - struct ec_host_request *r = (struct ec_host_request *)in_msg; - - /* Store request data from Rx FIFO to in_msg buffer */ - spi_host_request_data(in_msg, sizeof(*r)); - - /* Protocol version 3 */ - if (in_msg[0] == EC_HOST_REQUEST_VERSION) { - int pkt_size; - - /* Check how big the packet should be */ - pkt_size = host_request_expected_size(r); - - if (pkt_size == 0 || pkt_size > sizeof(in_msg)) { - spi_bad_received_data(pkt_size); - return; - } - - /* Store request data from Rx FIFO to in_msg buffer */ - spi_host_request_data(in_msg + sizeof(*r), - pkt_size - sizeof(*r)); - - /* Set up parameters for host request */ - spi_packet.send_response = spi_send_response_packet; - spi_packet.request = in_msg; - spi_packet.request_temp = NULL; - spi_packet.request_max = sizeof(in_msg); - spi_packet.request_size = pkt_size; - - /* Response must start with the preamble */ - memcpy(out_msg, out_preamble, sizeof(out_preamble)); - - spi_packet.response = out_msg + EC_SPI_PREAMBLE_LENGTH; - /* Reserve space for frame start and trailing past-end byte */ - spi_packet.response_max = SPI_MAX_RESPONSE_SIZE; - spi_packet.response_size = 0; - spi_packet.driver_result = EC_RES_SUCCESS; - - /* Go to common-layer to handle request */ - host_packet_receive(&spi_packet); - } else { - /* Invalid version number */ - CPRINTS("Invalid version number"); - spi_bad_received_data(1); - } -} - -static void shi_ite_int_handler(const void *arg) -{ - /* - * The status of SPI end detection interrupt bit is set, it - * means that host command parse has been completed and AP - * has received the last byte which is EC_SPI_PAST_END from - * EC responded data, then AP ended the transaction. - */ - if (IT83XX_SPI_ISR & IT83XX_SPI_ENDDETECTINT) { - /* Disable CPU access Rx FIFO to clock in data from AP again */ - IT83XX_SPI_TXRXFAR = 0; - /* Ready to receive */ - spi_set_state(SPI_STATE_READY_TO_RECV); - /* - * Once there is no SPI active, enable idle task deep - * sleep bit of SPI in S3 or lower. - * TODO(b:185176098): enable_sleep(SLEEP_MASK_SPI); - */ - - /* CS# is deasserted, so write clear all slave status */ - IT83XX_SPI_ISR = 0xff; - } - /* - * The status of Rx valid length interrupt bit is set that - * indicates reached target count(IT83XX_SPI_FTCB1R, - * IT83XX_SPI_FTCB0R) and the length field of the host - * requested data. - */ - if (IT83XX_SPI_RX_VLISR & IT83XX_SPI_RVLI) { - /* write clear slave status */ - IT83XX_SPI_RX_VLISR = IT83XX_SPI_RVLI; - /* Move to processing state */ - spi_set_state(SPI_STATE_PROCESSING); - /* Parse header for version of spi-protocol */ - spi_parse_header(); - } -} - -void spi_event(enum gpio_signal signal) -{ - if (chipset_in_state(CHIPSET_STATE_ON)) { - /* Move to processing state */ - spi_set_state(SPI_STATE_PROCESSING); - /* Disable idle task deep sleep bit of SPI in S0. */ - /* TODO(b:185176098): disable_sleep(SLEEP_MASK_SPI); */ - } -} - -/* - * SHI init priority is behind CONFIG_PLATFORM_EC_GPIO_INIT_PRIORITY to - * overwrite GPIO_INPUT setting of spi chip select pin. - */ -static int cros_shi_ite_init(const struct device *dev) -{ - const struct cros_shi_it8xxx2_cfg *const config = DRV_CONFIG(dev); - /* Set FIFO data target count */ - struct ec_host_request cmd_head; - - /* - * Target count means the size of host request. - * And plus extra 4 bytes because the CPU accesses FIFO base on - * word. If host requested data length is one byte, we need to - * align the data length to 4 bytes. - */ - int target_count = sizeof(cmd_head) + 4; - /* Offset of data_len member of host request. */ - int offset = (char *)&cmd_head.data_len - (char *)&cmd_head; - - IT83XX_SPI_FTCB1R = (target_count >> 8) & 0xff; - IT83XX_SPI_FTCB0R = target_count & 0xff; - /* - * The register setting can capture the length field of host - * request. - */ - IT83XX_SPI_TCCB1 = (offset >> 8) & 0xff; - IT83XX_SPI_TCCB0 = offset & 0xff; - - /* - * Memory controller configuration register 3. - * bit6 : SPI pin function select (0b:Enable, 1b:Mask) - */ - IT83XX_GCTRL_MCCR3 |= IT83XX_GCTRL_SPISLVPFE; - /* Set unused blocked byte */ - IT83XX_SPI_HPR2 = 0x00; - /* Rx valid length interrupt enabled */ - IT83XX_SPI_RX_VLISMR &= ~IT83XX_SPI_RVLIM; - /* - * General control register2 - * bit4 : Rx FIFO2 will not be overwrited once it's full. - * bit3 : Rx FIFO1 will not be overwrited once it's full. - * bit0 : Rx FIFO1/FIFO2 will reset after each CS_N goes high. - */ - IT83XX_SPI_GCR2 = IT83XX_SPI_RXF2OC | IT83XX_SPI_RXF1OC - | IT83XX_SPI_RXFAR; - /* - * Interrupt mask register (0b:Enable, 1b:Mask) - * bit5 : Rx byte reach interrupt mask - * bit2 : SPI end detection interrupt mask - */ - IT83XX_SPI_IMR &= ~IT83XX_SPI_EDIM; - /* Reset fifo and prepare to for next transaction */ - reset_rx_fifo(); - /* Ready to receive */ - spi_set_state(SPI_STATE_READY_TO_RECV); - /* Interrupt status register(write one to clear) */ - IT83XX_SPI_ISR = 0xff; - /* SPI slave controller enable (after settings are ready) */ - IT83XX_SPI_SPISGCR = IT83XX_SPI_SPISCEN; - - /* Ensure spi chip select alt function is enabled. */ - for (int i = 0; i < DT_INST_PROP_LEN(0, pinctrl_0); i++) { - pinmux_pin_set(config[i].pinctrls, config[i].pin, - config[i].alt_fun); - } - - /* Enable SPI slave interrupt */ - IRQ_CONNECT(DT_INST_IRQN(0), 0, shi_ite_int_handler, 0, 0); - irq_enable(DT_INST_IRQN(0)); - - /* Enable SPI chip select pin interrupt */ - gpio_enable_interrupt(GPIO_SPI0_CS); - - return 0; -} - -static const struct cros_shi_it8xxx2_cfg cros_shi_cfg[] = - IT8XXX2_DT_ALT_ITEMS_LIST(0); - -#if CONFIG_CROS_SHI_IT8XXX2_INIT_PRIORITY <= \ - CONFIG_PLATFORM_EC_GPIO_INIT_PRIORITY -#error "CROS_SHI must initialize after the GPIOs initialization" -#endif -DEVICE_DT_INST_DEFINE(0, cros_shi_ite_init, NULL, - NULL, &cros_shi_cfg, POST_KERNEL, - CONFIG_CROS_SHI_IT8XXX2_INIT_PRIORITY, - NULL); - -/* Get protocol information */ -enum ec_status spi_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 = SPI_MAX_REQUEST_SIZE; - r->max_response_packet_size = SPI_MAX_RESPONSE_SIZE; - r->flags = EC_PROTOCOL_INFO_IN_PROGRESS_SUPPORTED; - - args->response_size = sizeof(*r); - - return EC_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_GET_PROTOCOL_INFO, - spi_get_protocol_info, - EC_VER_MASK(0)); diff --git a/zephyr/drivers/cros_shi/cros_shi_npcx.c b/zephyr/drivers/cros_shi/cros_shi_npcx.c deleted file mode 100644 index a290e320fc..0000000000 --- a/zephyr/drivers/cros_shi/cros_shi_npcx.c +++ /dev/null @@ -1,899 +0,0 @@ -/* 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 SPI controller 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_MS 9 - -/* - * 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; - - /* - * Disable interrupts in case the interfere by the other interrupts. - * Use __disable_irq/__enable_irq instead of using irq_lock/irq_unlock - * here because irq_lock/irq_unlock leave some system exceptions (like - * SVC, NMI, and faults) still enabled. - */ - __disable_irq(); - - /* - * 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 */ - __enable_irq(); -} - -/* 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); - - /* - * 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. - */ - __disable_irq(); - - 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); - - __enable_irq(); -} - -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_MS; - - /* 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); - - /* - * 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); - - return 0; -} - -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 *clk_dev = DEVICE_DT_GET(NPCX_CLK_CTRL_NODE); - - /* 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; - } - - /* If booter doesn't set the host interface type */ - if (!NPCX_BOOTER_IS_HIF_TYPE_SET()) { - npcx_host_interface_sel(NPCX_HIF_TYPE_ESPI_SHI); - } - - /* - * 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, /* pm_control_fn= */ NULL, - &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); |