/* * 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: * * [...] * * 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));