summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortim <tim2.lin@ite.corp-partner.google.com>2021-03-22 08:23:08 +0800
committerCommit Bot <commit-bot@chromium.org>2021-04-21 16:08:54 +0000
commit16f1f97ff6d453191689fa4cda61aae34f9e2c58 (patch)
treee20cfec810c98577a88bd6bd2c2a1c97952810af
parent9ef1edbc3bc25988acf8d40c24002d961ccea86d (diff)
downloadchrome-ec-16f1f97ff6d453191689fa4cda61aae34f9e2c58.tar.gz
zephyr/drivers: it8xxx2: add SPI host interface driver
Add spi host interface driver which is required to communicate with the EC when the CPU is the ARM processor. BUG=b:185202623 BRANCH=none TEST=replaced board hayato's EC with it81202_evb and the host command can be received and responded. Signed-off-by: tim <tim2.lin@ite.corp-partner.google.com> Change-Id: I25ccdd0b29bf46b6a4ad451150f63b47dc9d3b97 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2813841 Reviewed-by: Jack Rosenthal <jrosenth@chromium.org> Reviewed-by: Denis Brockus <dbrockus@chromium.org> Commit-Queue: Jack Rosenthal <jrosenth@chromium.org>
-rw-r--r--zephyr/drivers/cros_shi/CMakeLists.txt1
-rw-r--r--zephyr/drivers/cros_shi/Kconfig8
-rw-r--r--zephyr/drivers/cros_shi/cros_shi_it8xxx2.c342
3 files changed, 351 insertions, 0 deletions
diff --git a/zephyr/drivers/cros_shi/CMakeLists.txt b/zephyr/drivers/cros_shi/CMakeLists.txt
index 6bc531b185..f0b3c8bb5a 100644
--- a/zephyr/drivers/cros_shi/CMakeLists.txt
+++ b/zephyr/drivers/cros_shi/CMakeLists.txt
@@ -2,4 +2,5 @@
# 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
index 0d46fab3be..54c393e00f 100644
--- a/zephyr/drivers/cros_shi/Kconfig
+++ b/zephyr/drivers/cros_shi/Kconfig
@@ -33,3 +33,11 @@ config CROS_SHI_NPCX_DEBUG
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.
diff --git a/zephyr/drivers/cros_shi/cros_shi_it8xxx2.c b/zephyr/drivers/cros_shi/cros_shi_it8xxx2.c
new file mode 100644
index 0000000000..1fd3cc4e96
--- /dev/null
+++ b/zephyr/drivers/cros_shi/cros_shi_it8xxx2.c
@@ -0,0 +1,342 @@
+/* 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 "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 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)
+{
+ /* 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;
+}
+
+/*
+ * 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;
+
+ /* Move to processing state */
+ spi_set_state(SPI_STATE_PROCESSING);
+
+ /* 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) {
+ /* 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;
+ /* Parse header for version of spi-protocol */
+ spi_parse_header();
+ }
+
+}
+
+static int cros_shi_ite_init(const struct device *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;
+
+ /* Enable SPI slave interrupt */
+ IRQ_CONNECT(DT_INST_IRQN(0), 0, shi_ite_int_handler, 0, 0);
+ irq_enable(DT_INST_IRQN(0));
+
+ return 0;
+}
+SYS_INIT(cros_shi_ite_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
+
+/* 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));