/*
 * Copyright 2013 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.
 *
 * SPI driver for Chrome EC.
 *
 * This uses DMA to handle transmission and reception.
 */

#include "chipset.h"
#include "clock.h"
#include "console.h"
#include "dma.h"
#include "gpio.h"
#include "hooks.h"
#include "host_command.h"
#include "link_defs.h"
#include "registers.h"
#include "spi.h"
#include "stm32-dma.h"
#include "system.h"
#include "timer.h"
#include "util.h"

/* Console output macros */
#define CPUTS(outstr) cputs(CC_SPI, outstr)
#define CPRINTS(format, args...) cprints(CC_SPI, format, ## args)
#define CPRINTF(format, args...) cprintf(CC_SPI, format, ## args)

/* SPI FIFO registers */
#ifdef CHIP_FAMILY_STM32H7
#define SPI_TXDR REG8(&STM32_SPI1_REGS->txdr)
#define SPI_RXDR REG8(&STM32_SPI1_REGS->rxdr)
#else
#define SPI_TXDR STM32_SPI1_REGS->dr
#define SPI_RXDR STM32_SPI1_REGS->dr
#endif

/* DMA channel option */
static const struct dma_option dma_tx_option = {
	STM32_DMAC_SPI1_TX, (void *)&SPI_TXDR,
	STM32_DMA_CCR_MSIZE_8_BIT | STM32_DMA_CCR_PSIZE_8_BIT
#ifdef CHIP_FAMILY_STM32F4
	| STM32_DMA_CCR_CHANNEL(STM32_SPI1_TX_REQ_CH)
#endif
};

static const struct dma_option dma_rx_option = {
	STM32_DMAC_SPI1_RX, (void *)&SPI_RXDR,
	STM32_DMA_CCR_MSIZE_8_BIT | STM32_DMA_CCR_PSIZE_8_BIT
#ifdef CHIP_FAMILY_STM32F4
	| STM32_DMA_CCR_CHANNEL(STM32_SPI1_RX_REQ_CH)
#endif
};

/*
 * Timeout to wait for SPI 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 SPI interface, since running it slower
 * significantly impacts firmware update times.
 */
#define SPI_CMD_RX_TIMEOUT_US 8192

#ifdef CONFIG_SPI_PROTOCOL_V2
/*
 * 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 SPI_PROTO2_OFFSET (EC_PROTO2_RESPONSE_HEADER_BYTES + 2)
#define SPI_PROTO2_OVERHEAD (SPI_PROTO2_OFFSET +		\
			     EC_PROTO2_RESPONSE_TRAILER_BYTES + 1)
#endif /* defined(CONFIG_SPI_PROTOCOL_V2) */
/*
 * 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.
 */
#define SPI_MAX_REQUEST_SIZE 0x220
#define SPI_MAX_RESPONSE_SIZE 0x220

/*
 * 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.  Search for "spi-frame-header" in U-boot to see how that's
 * implemented.
 *
 * The preamble must be 32-bit aligned so that the response buffer is also
 * 32-bit aligned.
 */
static const uint8_t out_preamble[4] = {
	EC_SPI_PROCESSING,
	EC_SPI_PROCESSING,
	EC_SPI_PROCESSING,
	EC_SPI_FRAME_START,  /* This is the byte which matters */
};

/*
 * Space allocation of the past-end status byte (EC_SPI_PAST_END) in the out_msg
 * buffer. This seems to be dynamic because the F0 family needs to send it 4
 * times in order to make sure it actually stays at the repeating byte after DMA
 * ends.
 *
 * See crosbug.com/p/31390
 */
#if defined(CHIP_FAMILY_STM32F0) || defined(CHIP_FAMILY_STM32L4)
#define EC_SPI_PAST_END_LENGTH 4
#else
#define EC_SPI_PAST_END_LENGTH 1
#endif

/*
 * Our input and output buffers. These must be large enough for our largest
 * message, including protocol overhead, and must be 32-bit aligned.
 */
static uint8_t out_msg[SPI_MAX_RESPONSE_SIZE + sizeof(out_preamble) +
	EC_SPI_PAST_END_LENGTH] __aligned(4) __uncached;
static uint8_t in_msg[SPI_MAX_REQUEST_SIZE] __aligned(4) __uncached;
static uint8_t enabled;
#ifdef CONFIG_SPI_PROTOCOL_V2
static struct host_cmd_handler_args args;
#endif
static struct host_packet spi_packet;

/*
 * This is set if SPI NSS raises to high while EC is still processing a
 * command.
 */
static int setup_transaction_later;

enum spi_state {
	/* SPI not enabled (initial state, and when chipset is off) */
	SPI_STATE_DISABLED = 0,

	/* Setting up receive DMA */
	SPI_STATE_PREPARE_RX,

	/* Ready to receive next request */
	SPI_STATE_READY_TO_RX,

	/* Receiving request */
	SPI_STATE_RECEIVING,

	/* Processing request */
	SPI_STATE_PROCESSING,

	/* Sending response */
	SPI_STATE_SENDING,

	/*
	 * Received bad data - transaction started before we were ready, or
	 * packet header from host didn't parse properly.  Ignoring received
	 * data.
	 */
	SPI_STATE_RX_BAD,
} state;

/**
 * Wait until we have received a certain number of bytes
 *
 * Watch the DMA receive channel until it has the required number of bytes,
 * or a timeout occurs
 *
 * We keep an eye on the NSS line - if this goes high then the transaction is
 * over so there is no point in trying to receive the bytes.
 *
 * @param rxdma		RX DMA channel to watch
 * @param needed	Number of bytes that are needed
 * @param nss		GPIO signal for NSS control line
 * @return 0 if bytes received, -1 if we hit a timeout or NSS went high
 */
static int wait_for_bytes(dma_chan_t *rxdma, int needed,
			  enum gpio_signal nss)
{
	timestamp_t deadline;

	ASSERT(needed <= sizeof(in_msg));
	deadline.val = 0;
	while (1) {
		if (dma_bytes_done(rxdma, sizeof(in_msg)) >= needed)
			return 0;
		if (gpio_get_level(nss))
			return -1;
		if (!deadline.val) {
			deadline = get_time();
			deadline.val += SPI_CMD_RX_TIMEOUT_US;
		}
		if (timestamp_expired(deadline, NULL))
			return -1;
	}
}

#ifdef CONFIG_SPI_PROTOCOL_V2
/**
 * Send a reply on a given port.
 *
 * The format of a reply is as per the command interface, with a number of
 * preamble bytes before it.
 *
 * The format of a reply is a sequence of bytes:
 *
 * <hdr> <status> <len> <msg bytes> <sum> [<preamble byte>...]
 *
 * The hdr byte is just a tag to indicate that the real message follows. It
 * signals the end of any preamble required by the interface.
 *
 * The length is the entire packet size, including the header, length bytes,
 * message payload, checksum, and postamble byte.
 *
 * The preamble is at least 2 bytes, but can be longer if the STM takes ages
 * to react to the incoming message. Since we send our first byte as the AP
 * sends us the command, we clearly can't send anything sensible for that
 * byte. The second byte must be written to the output register just when the
 * command byte is ready (I think), so we can't do anything there either.
 * Any processing we do may increase this delay. That's the reason for the
 * preamble.
 *
 * It is interesting to note that it seems to be possible to run the SPI
 * interface faster than the CPU clock with this approach.
 *
 * We keep an eye on the NSS line - if this goes high then the transaction is
 * over so there is no point in trying to send the reply.
 *
 * @param txdma		TX DMA channel to send on
 * @param status	Status result to send
 * @param msg_ptr	Message payload to send, which normally starts
 *			SPI_PROTO2_OFFSET bytes into out_msg
 * @param msg_len	Number of message bytes to send
 */
static void reply(dma_chan_t *txdma,
		  enum ec_status status, char *msg_ptr, int msg_len)
{
	char *msg = out_msg;
	int need_copy = msg_ptr != msg + SPI_PROTO2_OFFSET;
	int sum, i;

	ASSERT(msg_len + SPI_PROTO2_OVERHEAD <= sizeof(out_msg));

	/* Add our header bytes - the first one might not actually be sent */
	msg[0] = EC_SPI_PROCESSING;
	msg[1] = EC_SPI_FRAME_START;
	msg[2] = status;
	msg[3] = msg_len & 0xff;

	/*
	 * Calculate the checksum; includes the status and message length bytes
	 * but not the pad and framing bytes since those are stripped by the AP
	 * driver.
	 */
	sum = status + msg_len;
	for (i = 0; i < msg_len; i++) {
		int ch = msg_ptr[i];
		sum += ch;
		if (need_copy)
			msg[i + SPI_PROTO2_OFFSET] = ch;
	}

	/* Add the checksum and get ready to send */
	msg[SPI_PROTO2_OFFSET + msg_len] = sum & 0xff;
	msg[SPI_PROTO2_OFFSET + msg_len + 1] = EC_SPI_PAST_END;
	dma_prepare_tx(&dma_tx_option, msg_len + SPI_PROTO2_OVERHEAD, msg);

	/* Kick off the DMA to send the data */
	dma_go(txdma);
}
#endif /* defined(CONFIG_SPI_PROTOCOL_V2) */

/**
 * Sends a byte over SPI without DMA
 *
 * This is mostly used when we want to relay status bytes to the AP while we're
 * receiving the message and we're thinking about it.
 *
 * @note It may be sent 0, 1, or >1 times, depending on whether the host clocks
 * the bus or not. Basically, the EC is saying "if you ask me what my status is,
 * you'll get this value.  But you're not required to ask, or you can ask
 * multiple times."
 *
 * @param byte	status byte to send, one of the EC_SPI_* #defines from
 *		ec_commands.h
 */
static void tx_status(uint8_t byte)
{
	stm32_spi_regs_t *spi __attribute__((unused)) = STM32_SPI1_REGS;

	SPI_TXDR = byte;
#if defined(CHIP_FAMILY_STM32F0) || defined(CHIP_FAMILY_STM32L4)
	/* It sends the byte 4 times in order to be sure it bypassed the FIFO
	 * from the STM32F0 line.
	 */
	spi->dr = byte;
	spi->dr = byte;
	spi->dr = byte;
#elif defined(CHIP_FAMILY_STM32H7)
	spi->udrdr = byte;
#endif
}

/**
 * Get ready to receive a message from the master.
 *
 * Set up our RX DMA and disable our TX DMA. Set up the data output so that
 * we will send preamble bytes.
 */
static void setup_for_transaction(void)
{
	stm32_spi_regs_t *spi __attribute__((unused)) = STM32_SPI1_REGS;
	volatile uint8_t dummy __attribute__((unused));

	/* clear this as soon as possible */
	setup_transaction_later = 0;

#ifndef CHIP_FAMILY_STM32H7 /* H7 is not ready to set status here */
	/* Not ready to receive yet */
	tx_status(EC_SPI_NOT_READY);
#endif

	/* We are no longer actively processing a transaction */
	state = SPI_STATE_PREPARE_RX;

	/* Stop sending response, if any */
	dma_disable(STM32_DMAC_SPI1_TX);

	/*
	 * Read dummy bytes in case there are some pending; this prevents the
	 * receive DMA from getting that byte right when we start it.
	 */
	dummy = SPI_RXDR;
#if defined(CHIP_FAMILY_STM32F0) || defined(CHIP_FAMILY_STM32L4)
	/* 4 Bytes makes sure the RX FIFO on the F0 is empty as well. */
	dummy = spi->dr;
	dummy = spi->dr;
	dummy = spi->dr;
#endif

	/* Start DMA */
	dma_start_rx(&dma_rx_option, sizeof(in_msg), in_msg);

	/* Ready to receive */
	state = SPI_STATE_READY_TO_RX;
	tx_status(EC_SPI_OLD_READY);

#ifdef CHIP_FAMILY_STM32H7
	spi->cr1 |= STM32_SPI_CR1_SPE;
#endif
}

/* Forward declaration */
static void spi_init(void);

/*
 * If a setup_for_transaction() was postponed, call it now.
 * Note that setup_for_transaction() cancels Tx DMA.
 */
static void check_setup_transaction_later(void)
{
	if (setup_transaction_later) {
		spi_init(); /* Fix for bug chrome-os-partner:31390 */
		/*
		 * 'state' is set to SPI_STATE_READY_TO_RX. Somehow AP
		 * de-asserted the SPI NSS during the handler was running.
		 * Thus, the pending result will be dropped anyway.
		 */
	}
}

#ifdef CONFIG_SPI_PROTOCOL_V2
/**
 * Called for V2 protocol to indicate that a command has completed
 *
 * Some commands can continue for a while. This function is called by
 * host_command when it completes.
 *
 */
static void spi_send_response(struct host_cmd_handler_args *args)
{
	enum ec_status result = args->result;
	dma_chan_t *txdma;

	/*
	 * If we're not processing, then the AP has already terminated the
	 * transaction, and won't be listening for a response.
	 */
	if (state != SPI_STATE_PROCESSING)
		return;

	/* state == SPI_STATE_PROCESSING */

	if (args->response_size > args->response_max)
		result = EC_RES_INVALID_RESPONSE;

	/* Transmit the reply */
	txdma = dma_get_channel(STM32_DMAC_SPI1_TX);
	reply(txdma, result, args->response, args->response_size);

	/*
	 * Before the state is set to SENDING, any CS de-assertion would
	 * set setup_transaction_later to 1.
	 */
	state = SPI_STATE_SENDING;
	check_setup_transaction_later();
}
#endif /* defined(CONFIG_SPI_PROTOCOL_V2) */

/**
 * 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)
{
	dma_chan_t *txdma;

	/*
	 * If we're not processing, then the AP has already terminated the
	 * transaction, and won't be listening for a response.
	 */
	if (state != SPI_STATE_PROCESSING)
		return;

	/* state == SPI_STATE_PROCESSING */

	/* Append our past-end byte, which we reserved space for. */
	((uint8_t *)pkt->response)[pkt->response_size + 0] = EC_SPI_PAST_END;
#if defined(CHIP_FAMILY_STM32F0) || defined(CHIP_FAMILY_STM32L4)
	/* Make sure we are going to be outputting it properly when the DMA
	 * ends due to the TX FIFO bug on the F0. See crosbug.com/p/31390
	 */
	((uint8_t *)pkt->response)[pkt->response_size + 1] = EC_SPI_PAST_END;
	((uint8_t *)pkt->response)[pkt->response_size + 2] = EC_SPI_PAST_END;
	((uint8_t *)pkt->response)[pkt->response_size + 3] = EC_SPI_PAST_END;
#endif

	/* Transmit the reply */
	txdma = dma_get_channel(STM32_DMAC_SPI1_TX);
	dma_prepare_tx(&dma_tx_option, sizeof(out_preamble) + pkt->response_size
		+ EC_SPI_PAST_END_LENGTH, out_msg);
	dma_go(txdma);
#ifdef CHIP_FAMILY_STM32H7
	/* clear any previous underrun */
	STM32_SPI1_REGS->ifcr = STM32_SPI_SR_UDR;
#endif /* CHIP_FAMILY_STM32H7 */

	/*
	 * Before the state is set to SENDING, any CS de-assertion would
	 * set setup_transaction_later to 1.
	 */
	state = SPI_STATE_SENDING;
	check_setup_transaction_later();
}

/**
 * Handle an event on the NSS pin
 *
 * A falling edge of NSS indicates that the master is starting a new
 * transaction. A rising edge indicates that we have finished.
 *
 * @param signal	GPIO signal for the NSS pin
 */
void spi_event(enum gpio_signal signal)
{
	dma_chan_t *rxdma;
	uint16_t i;

	/* If not enabled, ignore glitches on NSS */
	if (!enabled)
		return;

	/* Check chip select.  If it's high, the AP ended a transaction. */
	if (gpio_get_level(GPIO_SPI1_NSS)) {
		enable_sleep(SLEEP_MASK_SPI);

		/*
		 * If the buffer is still used by the host command, postpone
		 * the DMA rx setup.
		 */
		if (state == SPI_STATE_PROCESSING) {
			setup_transaction_later = 1;
			return;
		}

		/* Set up for the next transaction */
		spi_init(); /* Fix for bug chrome-os-partner:31390 */
		return;
	}
	disable_sleep(SLEEP_MASK_SPI);

	/* Chip select is low = asserted */
	if (state != SPI_STATE_READY_TO_RX) {
		/*
		 * AP started a transaction but we weren't ready for it.
		 * Tell AP we weren't ready, and ignore the received data.
		 */
		CPRINTS("SPI not ready");
		tx_status(EC_SPI_NOT_READY);
		state = SPI_STATE_RX_BAD;
		return;
	}

	/* We're now inside a transaction */
	state = SPI_STATE_RECEIVING;
	tx_status(EC_SPI_RECEIVING);
	rxdma = dma_get_channel(STM32_DMAC_SPI1_RX);

	/* Wait for version, command, length bytes */
	if (wait_for_bytes(rxdma, 3, GPIO_SPI1_NSS))
		goto spi_event_error;

	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;

		/* Wait for the rest of the command header */
		if (wait_for_bytes(rxdma, sizeof(*r), GPIO_SPI1_NSS))
			goto spi_event_error;

		/*
		 * Check how big the packet should be.  We can't just wait to
		 * see how much data the host sends, because it will keep
		 * sending dummy data until we respond.
		 */
		pkt_size = host_request_expected_size(r);
		if (pkt_size == 0 || pkt_size > sizeof(in_msg))
			goto spi_event_error;

		/* Wait for the packet data */
		if (wait_for_bytes(rxdma, pkt_size, GPIO_SPI1_NSS))
			goto spi_event_error;

		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 + sizeof(out_preamble);
		/* Reserve space for the preamble and trailing past-end byte */
		spi_packet.response_max = sizeof(out_msg)
			- sizeof(out_preamble) - EC_SPI_PAST_END_LENGTH;
		spi_packet.response_size = 0;

		spi_packet.driver_result = EC_RES_SUCCESS;

		/* Move to processing state */
		state = SPI_STATE_PROCESSING;
		tx_status(EC_SPI_PROCESSING);

		host_packet_receive(&spi_packet);
		return;

	} else if (in_msg[0] >= EC_CMD_VERSION0) {
#ifdef CONFIG_SPI_PROTOCOL_V2
		/*
		 * Protocol version 2
		 *
		 * TODO(crosbug.com/p/20257): Remove once kernel supports
		 * version 3.
		 */

#ifdef CHIP_FAMILY_STM32F0
		CPRINTS("WARNING: Protocol version 2 is not supported on the F0"
			" line due to crosbug.com/p/31390");
#endif

		args.version = in_msg[0] - EC_CMD_VERSION0;
		args.command = in_msg[1];
		args.params_size = in_msg[2];

		/* Wait for parameters */
		if (wait_for_bytes(rxdma, 3 + args.params_size, GPIO_SPI1_NSS))
			goto spi_event_error;

		/*
		 * Params are not 32-bit aligned in protocol version 2.  As a
		 * workaround, move them to the beginning of the input buffer
		 * so they are aligned.
		 */
		if (args.params_size)
			memmove(in_msg, in_msg + 3, args.params_size);

		args.params = in_msg;
		args.send_response = spi_send_response;

		/* Allow room for the header bytes */
		args.response = out_msg + SPI_PROTO2_OFFSET;
		args.response_max = sizeof(out_msg) - SPI_PROTO2_OVERHEAD;
		args.response_size = 0;
		args.result = EC_RES_SUCCESS;

		/* Move to processing state */
		state = SPI_STATE_PROCESSING;
		tx_status(EC_SPI_PROCESSING);

		host_command_received(&args);
		return;
#else /* !defined(CONFIG_SPI_PROTOCOL_V2) */
		/* Protocol version 2 is deprecated. */
		CPRINTS("ERROR: Protocol V2 is not supported!");
#endif /* defined(CONFIG_SPI_PROTOCOL_V2) */
	}

 spi_event_error:
	/* Error, timeout, or protocol we can't handle.  Ignore data. */
	tx_status(EC_SPI_RX_BAD_DATA);
	state = SPI_STATE_RX_BAD;
	CPRINTS("SPI rx bad data");

	CPRINTF("in_msg=[");
	for (i = 0; i < dma_bytes_done(rxdma, sizeof(in_msg)); i++)
		CPRINTF("%02x ", in_msg[i]);
	CPRINTF("]\n");
}

static void spi_chipset_startup(void)
{
	/* Enable pullup and interrupts on NSS */
	gpio_set_flags(GPIO_SPI1_NSS, GPIO_INT_BOTH | GPIO_PULL_UP);

	/* Set SPI pins to alternate function */
	gpio_config_module(MODULE_SPI, 1);

	/* Set up for next transaction */
	setup_for_transaction();

	enabled = 1;
}
DECLARE_HOOK(HOOK_CHIPSET_RESUME, spi_chipset_startup, HOOK_PRIO_DEFAULT);

static void spi_chipset_shutdown(void)
{
	enabled = 0;
	state = SPI_STATE_DISABLED;

	/* Disable pullup and interrupts on NSS */
	gpio_set_flags(GPIO_SPI1_NSS, GPIO_INPUT);

	/* Set SPI pins to inputs so we don't leak power when AP is off */
	gpio_config_module(MODULE_SPI, 0);

	/* Allow deep sleep when AP off */
	enable_sleep(SLEEP_MASK_SPI);
}
DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, spi_chipset_shutdown, HOOK_PRIO_DEFAULT);

static void spi_init(void)
{
	stm32_spi_regs_t *spi = STM32_SPI1_REGS;
	uint8_t was_enabled = enabled;

	/* Reset the SPI Peripheral to clear any existing weird states. */
	/* Fix for bug chrome-os-partner:31390 */
	enabled = 0;
	state = SPI_STATE_DISABLED;
	STM32_RCC_APB2RSTR |= STM32_RCC_PB2_SPI1;
	STM32_RCC_APB2RSTR &= ~STM32_RCC_PB2_SPI1;

	/* 40 MHz pin speed */
	STM32_GPIO_OSPEEDR(GPIO_A) |= 0xff00;

	/* Enable clocks to SPI1 module */
	STM32_RCC_APB2ENR |= STM32_RCC_PB2_SPI1;

	/* Delay 1 APB clock cycle after the clock is enabled */
	clock_wait_bus_cycles(BUS_APB, 1);

	/*
	 * Select the right DMA request for the variants using it.
	 * This is not required for STM32F4 since the channel (aka request) is
	 * set directly in the respective dma_option. In fact, it would be
	 * overridden in dma-stm32f4::prepare_stream().
	 */
#ifdef CHIP_FAMILY_STM32L4
	dma_select_channel(STM32_DMAC_SPI1_TX, 1);
	dma_select_channel(STM32_DMAC_SPI1_RX, 1);
#elif defined(CHIP_FAMILY_STM32H7)
	dma_select_channel(STM32_DMAC_SPI1_TX, DMAMUX1_REQ_SPI1_TX);
	dma_select_channel(STM32_DMAC_SPI1_RX, DMAMUX1_REQ_SPI1_RX);
#endif
	/*
	 * Enable rx/tx DMA and get ready to receive our first transaction and
	 * "disable" FIFO by setting event to happen after only 1 byte
	 */
#ifdef CHIP_FAMILY_STM32H7
	spi->cfg2 = 0;
	spi->cfg1 = STM32_SPI_CFG1_DATASIZE(8) | STM32_SPI_CFG1_FTHLV(4) |
			STM32_SPI_CFG1_CRCSIZE(8) |
			STM32_SPI_CFG1_TXDMAEN | STM32_SPI_CFG1_RXDMAEN |
			STM32_SPI_CFG1_UDRCFG_CONST |
			STM32_SPI_CFG1_UDRDET_BEGIN_FRM;
	spi->cr1 = 0;
#else /* !CHIP_FAMILY_STM32H7 */
	spi->cr2 = STM32_SPI_CR2_RXDMAEN | STM32_SPI_CR2_TXDMAEN |
		STM32_SPI_CR2_FRXTH | STM32_SPI_CR2_DATASIZE(8);

	/* Enable the SPI peripheral */
	spi->cr1 |= STM32_SPI_CR1_SPE;
#endif /* !CHIP_FAMILY_STM32H7 */

	gpio_enable_interrupt(GPIO_SPI1_NSS);

	/*
	 * If we were already enabled or chipset is already on,
	 * prepare for transaction
	 */
	if (was_enabled || chipset_in_state(CHIPSET_STATE_ON))
		spi_chipset_startup();
}
DECLARE_HOOK(HOOK_INIT, spi_init, HOOK_PRIO_INIT_SPI);

/**
 * Get protocol information
 */
static 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));
#ifdef CONFIG_SPI_PROTOCOL_V2
	r->protocol_versions |= BIT(2);
#endif
	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_RES_SUCCESS;
}
DECLARE_HOST_COMMAND(EC_CMD_GET_PROTOCOL_INFO,
		     spi_get_protocol_info,
		     EC_VER_MASK(0));
