summaryrefslogtreecommitdiff
path: root/chip/stm32/usb_spi.c
diff options
context:
space:
mode:
Diffstat (limited to 'chip/stm32/usb_spi.c')
-rw-r--r--chip/stm32/usb_spi.c627
1 files changed, 0 insertions, 627 deletions
diff --git a/chip/stm32/usb_spi.c b/chip/stm32/usb_spi.c
deleted file mode 100644
index 54caae015e..0000000000
--- a/chip/stm32/usb_spi.c
+++ /dev/null
@@ -1,627 +0,0 @@
-/* Copyright 2014 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.
- */
-
-#include "common.h"
-#include "link_defs.h"
-#include "registers.h"
-#include "spi.h"
-#include "usb_descriptor.h"
-#include "usb_hw.h"
-#include "usb_spi.h"
-#include "util.h"
-
-/* Forward declare platform specific functions. */
-static bool usb_spi_received_packet(struct usb_spi_config const *config);
-static bool usb_spi_transmitted_packet(struct usb_spi_config const *config);
-static void usb_spi_read_packet(struct usb_spi_config const *config,
- struct usb_spi_packet_ctx *packet);
-static void usb_spi_write_packet(struct usb_spi_config const *config,
- struct usb_spi_packet_ctx *packet);
-
-/*
- * Map EC error codes to USB_SPI error codes.
- *
- * @param error EC error code
- *
- * @returns USB SPI error code based on the mapping.
- */
-static int16_t usb_spi_map_error(int error)
-{
- switch (error) {
- case EC_SUCCESS: return USB_SPI_SUCCESS;
- case EC_ERROR_TIMEOUT: return USB_SPI_TIMEOUT;
- case EC_ERROR_BUSY: return USB_SPI_BUSY;
- default: return USB_SPI_UNKNOWN_ERROR | (error & 0x7fff);
- }
-}
-
-/*
- * Read data into the receive buffer.
- *
- * @param dst Destination receive context we are writing data to.
- * @param src Source packet context we are reading data from.
- *
- * @returns USB_SPI_RX_DATA_OVERFLOW if the source packet is too large
- */
-static int usb_spi_read_usb_packet(struct usb_spi_transfer_ctx *dst,
- const struct usb_spi_packet_ctx *src)
-{
- size_t max_read_length = dst->transfer_size - dst->transfer_index;
- size_t bytes_in_buffer = src->packet_size - src->header_size;
- const uint8_t *packet_buffer = src->bytes + src->header_size;
-
- if (bytes_in_buffer > max_read_length) {
- /*
- * An error occurred, we should not receive more data than
- * the buffer can support.
- */
- return USB_SPI_RX_DATA_OVERFLOW;
- }
- memcpy(dst->buffer + dst->transfer_index, packet_buffer,
- bytes_in_buffer);
-
- dst->transfer_index += bytes_in_buffer;
- return USB_SPI_SUCCESS;
-}
-
-/*
- * Fill the USB packet with data from the transmit buffer.
- *
- * @param dst Destination packet context we are writing data to.
- * @param src Source transmit context we are reading data from.
- */
-static void usb_spi_fill_usb_packet(struct usb_spi_packet_ctx *dst,
- struct usb_spi_transfer_ctx *src)
-{
- size_t transfer_size = src->transfer_size - src->transfer_index;
- size_t max_buffer_size = USB_MAX_PACKET_SIZE - dst->header_size;
- uint8_t *packet_buffer = dst->bytes + dst->header_size;
-
- if (transfer_size > max_buffer_size)
- transfer_size = max_buffer_size;
-
- memcpy(packet_buffer, src->buffer + src->transfer_index, transfer_size);
-
- dst->packet_size = dst->header_size + transfer_size;
- src->transfer_index += transfer_size;
-}
-
-/*
- * Setup the USB SPI state to start a new SPI transfer.
- *
- * @param config USB SPI config
- * @param write_count Number of bytes to write in the SPI transfer
- * @param read_count Number of bytes to read in the SPI transfer
- */
-static void usb_spi_setup_transfer(struct usb_spi_config const *config,
- size_t write_count, size_t read_count)
-{
- /* Reset any status code. */
- config->state->status_code = USB_SPI_SUCCESS;
-
- /* Reset the write and read counts. */
- config->state->spi_write_ctx.transfer_size = write_count;
- config->state->spi_write_ctx.transfer_index = 0;
- config->state->spi_read_ctx.transfer_size = read_count;
- config->state->spi_read_ctx.transfer_index = 0;
-}
-
-/*
- * Handle USB events that will reset the USB SPI state.
- *
- * @param config USB SPI config
- */
-static void usb_spi_reset_interface(struct usb_spi_config const *config)
-{
- /* Setup a 0 byte transfer to clear the contexts. */
- usb_spi_setup_transfer(config, 0, 0);
-}
-
-/*
- * Returns if the response transfer is in progress.
- *
- * @param config USB SPI config
- *
- * @returns True if a response transfer is in progress.
- */
-static bool usb_spi_response_in_progress(struct usb_spi_config const *config)
-{
- if ((config->state->mode == USB_SPI_MODE_START_RESPONSE) ||
- (config->state->mode == USB_SPI_MODE_CONTINUE_RESPONSE)) {
- return true;
- }
- return false;
-}
-
-/*
- * Prep the state to construct a new response. This sets the transfer
- * contexts, the mode, and status code. If a non-zero status code is
- * returned, then no payload will be transmitted.
- *
- * @param config USB SPI config
- * @param status_code status code to set for the response.
- */
-static void setup_transfer_response(struct usb_spi_config const *config,
- uint16_t status_code)
-{
- config->state->status_code = status_code;
- config->state->spi_read_ctx.transfer_index = 0;
- config->state->mode = USB_SPI_MODE_START_RESPONSE;
-
- /* If an error occurred, transmit an empty start packet. */
- if (status_code != USB_SPI_SUCCESS)
- config->state->spi_read_ctx.transfer_size = 0;
-}
-
-/*
- * Constructs the response packet containing the SPI configuration.
- *
- * @param config USB SPI config
- * @param packet Packet buffer we will be transmitting.
- */
-static void create_spi_config_response(struct usb_spi_config const *config,
- struct usb_spi_packet_ctx *packet)
-{
- /* Construct the response packet. */
- packet->rsp_config.packet_id = USB_SPI_PKT_ID_RSP_USB_SPI_CONFIG;
- packet->rsp_config.max_write_count = USB_SPI_MAX_WRITE_COUNT;
- packet->rsp_config.max_read_count = USB_SPI_MAX_READ_COUNT;
- /* Set the feature flags. */
- packet->rsp_config.feature_bitmap = 0;
-#ifndef CONFIG_SPI_HALFDUPLEX
- packet->rsp_config.feature_bitmap |=
- USB_SPI_FEATURE_FULL_DUPLEX_SUPPORTED;
-#endif
- packet->packet_size =
- sizeof(struct usb_spi_response_configuration_v2);
-}
-
-/*
- * If we have a transfer response in progress, this will construct the
- * next entry. If no transfer is in progress or if we are unable to
- * create the next packet, it will not modify tx_packet.
- *
- * @param config USB SPI config
- * @param packet Packet buffer we will be transmitting.
- */
-static void usb_spi_create_spi_transfer_response(
- struct usb_spi_config const *config,
- struct usb_spi_packet_ctx *transmit_packet)
-{
-
- if (!usb_spi_response_in_progress(config))
- return;
-
- if (config->state->spi_read_ctx.transfer_index == 0) {
-
- /* Transmit the first packet with the status code. */
- transmit_packet->header_size =
- offsetof(struct usb_spi_response_v2, data);
- transmit_packet->rsp_start.packet_id =
- USB_SPI_PKT_ID_RSP_TRANSFER_START;
- transmit_packet->rsp_start.status_code =
- config->state->status_code;
-
- usb_spi_fill_usb_packet(transmit_packet,
- &config->state->spi_read_ctx);
- } else if (config->state->spi_read_ctx.transfer_index <
- config->state->spi_read_ctx.transfer_size) {
-
- /* Transmit the continue packets. */
- transmit_packet->header_size =
- offsetof(struct usb_spi_continue_v2, data);
- transmit_packet->rsp_continue.packet_id =
- USB_SPI_PKT_ID_RSP_TRANSFER_CONTINUE;
- transmit_packet->rsp_continue.data_index =
- config->state->spi_read_ctx.transfer_index;
-
- usb_spi_fill_usb_packet(transmit_packet,
- &config->state->spi_read_ctx);
- }
- if (config->state->spi_read_ctx.transfer_index <
- config->state->spi_read_ctx.transfer_size) {
- config->state->mode = USB_SPI_MODE_CONTINUE_RESPONSE;
- } else {
- config->state->mode = USB_SPI_MODE_IDLE;
- }
-}
-
-/*
- * Process the rx packet.
- *
- * @param config USB SPI config
- * @param packet Received packet to process.
- */
-static void usb_spi_process_rx_packet(struct usb_spi_config const *config,
- struct usb_spi_packet_ctx *packet)
-{
- if (packet->packet_size < USB_SPI_MIN_PACKET_SIZE) {
- /* No valid packet exists smaller than the packet id. */
- setup_transfer_response(config, USB_SPI_RX_UNEXPECTED_PACKET);
- return;
- }
- /* Reset the mode until we've processed the packet. */
- config->state->mode = USB_SPI_MODE_IDLE;
-
- switch (packet->packet_id) {
- case USB_SPI_PKT_ID_CMD_GET_USB_SPI_CONFIG:
- {
- /* The host requires the SPI configuration. */
- config->state->mode = USB_SPI_MODE_SEND_CONFIGURATION;
- break;
- }
- case USB_SPI_PKT_ID_CMD_RESTART_RESPONSE:
- {
- /*
- * The host has requested the device restart the last response.
- * This is used to recover from lost USB packets without
- * duplicating SPI transfers.
- */
- setup_transfer_response(config, config->state->status_code);
- break;
- }
- case USB_SPI_PKT_ID_CMD_TRANSFER_START:
- {
- /* The host started a new USB SPI transfer */
- size_t write_count = packet->cmd_start.write_count;
- size_t read_count = packet->cmd_start.read_count;
-
- if (!config->state->enabled) {
- setup_transfer_response(config, USB_SPI_DISABLED);
- } else if (write_count > USB_SPI_MAX_WRITE_COUNT) {
- setup_transfer_response(config,
- USB_SPI_WRITE_COUNT_INVALID);
- } else if (read_count == USB_SPI_FULL_DUPLEX_ENABLED) {
-#ifndef CONFIG_SPI_HALFDUPLEX
- /* Full duplex mode is not supported on this device. */
- setup_transfer_response(config,
- USB_SPI_UNSUPPORTED_FULL_DUPLEX);
-#endif
- } else if (read_count > USB_SPI_MAX_READ_COUNT &&
- read_count != USB_SPI_FULL_DUPLEX_ENABLED) {
- setup_transfer_response(config,
- USB_SPI_READ_COUNT_INVALID);
- } else {
- usb_spi_setup_transfer(config, write_count, read_count);
- packet->header_size =
- offsetof(struct usb_spi_command_v2, data);
- config->state->status_code = usb_spi_read_usb_packet(
- &config->state->spi_write_ctx, packet);
- }
-
- /* Send responses if we encountered an error. */
- if (config->state->status_code != USB_SPI_SUCCESS) {
- setup_transfer_response(config,
- config->state->status_code);
- break;
- }
-
- /* Start the SPI transfer when we've read all data. */
- if (config->state->spi_write_ctx.transfer_index ==
- config->state->spi_write_ctx.transfer_size) {
- config->state->mode = USB_SPI_MODE_START_SPI;
- }
-
- break;
- }
- case USB_SPI_PKT_ID_CMD_TRANSFER_CONTINUE:
- {
- /*
- * The host has sent a continue packet for the SPI transfer
- * which contains additional data payload.
- */
- packet->header_size =
- offsetof(struct usb_spi_continue_v2, data);
- if (config->state->status_code == USB_SPI_SUCCESS) {
- config->state->status_code = usb_spi_read_usb_packet(
- &config->state->spi_write_ctx, packet);
- }
-
- /* Send responses if we encountered an error. */
- if (config->state->status_code != USB_SPI_SUCCESS) {
- setup_transfer_response(config,
- config->state->status_code);
- break;
- }
-
- /* Start the SPI transfer when we've read all data. */
- if (config->state->spi_write_ctx.transfer_index ==
- config->state->spi_write_ctx.transfer_size) {
- config->state->mode = USB_SPI_MODE_START_SPI;
- }
-
- break;
- }
- default:
- {
- /* An unknown USB packet was delivered. */
- setup_transfer_response(config, USB_SPI_RX_UNEXPECTED_PACKET);
- break;
- }
- }
-}
-
-/* Deferred function to handle state changes, process USB SPI packets,
- * and construct responses.
- *
- * @param config USB SPI config
- */
-void usb_spi_deferred(struct usb_spi_config const *config)
-{
- int enabled;
- struct usb_spi_packet_ctx *receive_packet =
- &config->state->receive_packet;
- struct usb_spi_packet_ctx *transmit_packet =
- &config->state->transmit_packet;
- transmit_packet->packet_size = 0;
-
- if (config->flags & USB_SPI_CONFIG_FLAGS_IGNORE_HOST_SIDE_ENABLE)
- enabled = config->state->enabled_device;
- else
- enabled = config->state->enabled_device &&
- config->state->enabled_host;
-
- /*
- * If our overall enabled state has changed we call the board specific
- * enable or disable routines and save our new state.
- */
- if (enabled != config->state->enabled) {
- if (enabled) usb_spi_board_enable(config);
- else usb_spi_board_disable(config);
-
- config->state->enabled = enabled;
- }
-
- /* Read any packets from the endpoint. */
-
- usb_spi_read_packet(config, receive_packet);
- if (receive_packet->packet_size) {
- usb_spi_process_rx_packet(config, receive_packet);
- }
-
- /* Need to send the USB SPI configuration */
- if (config->state->mode == USB_SPI_MODE_SEND_CONFIGURATION) {
- create_spi_config_response(config, transmit_packet);
- usb_spi_write_packet(config, transmit_packet);
- config->state->mode = USB_SPI_MODE_IDLE;
- return;
- }
-
- /* Start a new SPI transfer. */
- if (config->state->mode == USB_SPI_MODE_START_SPI) {
- uint16_t status_code;
- int read_count = config->state->spi_read_ctx.transfer_size;
-#ifndef CONFIG_SPI_HALFDUPLEX
- /*
- * Handle the full duplex mode on supported platforms.
- * The read count is equal to the write count.
- */
- if (read_count == USB_SPI_FULL_DUPLEX_ENABLED) {
- config->state->spi_read_ctx.transfer_size =
- config->state->spi_write_ctx.transfer_size;
- read_count = SPI_READBACK_ALL;
- }
-#endif
- status_code = spi_transaction(SPI_FLASH_DEVICE,
- config->state->spi_write_ctx.buffer,
- config->state->spi_write_ctx.transfer_size,
- config->state->spi_read_ctx.buffer,
- read_count);
-
- /* Cast the EC status code to USB SPI and start the response. */
- status_code = usb_spi_map_error(status_code);
- setup_transfer_response(config, status_code);
- }
-
- if (usb_spi_response_in_progress(config) &&
- usb_spi_transmitted_packet(config)) {
- usb_spi_create_spi_transfer_response(config, transmit_packet);
- usb_spi_write_packet(config, transmit_packet);
- }
-}
-
-/*
- * Sets which SPI modes will be enabled
- *
- * @param config USB SPI config
- * @param enabled usb_spi_request indicating which SPI mode is enabled.
- */
-void usb_spi_enable(struct usb_spi_config const *config, int enabled)
-{
- config->state->enabled_device = enabled;
-
- hook_call_deferred(config->deferred, 0);
-}
-
-/*
- * STM32 Platform: Receive the data from the endpoint into the packet and
- * mark the endpoint as ready to accept more data.
- *
- * @param config USB SPI config
- * @param packet Destination packet used to store the endpoint data.
- */
-static void usb_spi_read_packet(struct usb_spi_config const *config,
- struct usb_spi_packet_ctx *packet)
-{
- size_t packet_size;
-
- if (!usb_spi_received_packet(config)) {
- /* No data is present on the endpoint. */
- packet->packet_size = 0;
- return;
- }
-
- /* Copy bytes from endpoint memory. */
- packet_size = btable_ep[config->endpoint].rx_count & RX_COUNT_MASK;
- memcpy_from_usbram(packet->bytes,
- (void *)usb_sram_addr(config->ep_rx_ram), packet_size);
- packet->packet_size = packet_size;
- /* Set endpoint as valid for accepting new packet. */
- STM32_TOGGLE_EP(config->endpoint, EP_RX_MASK, EP_RX_VALID, 0);
-}
-
-/*
- * STM32 Platform: Transmit data from the packet to the endpoint buffer.
- * If a packet is written, the endpoint will be marked valid for transmitting.
- *
- * @param config USB SPI config
- * @param packet Source packet we will write to the endpoint data.
- */
-static void usb_spi_write_packet(struct usb_spi_config const *config,
- struct usb_spi_packet_ctx *packet)
-{
- if (packet->packet_size == 0)
- return;
-
- /* Copy bytes to endpoint memory. */
- memcpy_to_usbram((void *)usb_sram_addr(config->ep_tx_ram),
- packet->bytes, packet->packet_size);
- btable_ep[config->endpoint].tx_count = packet->packet_size;
-
- /* Mark the packet as having no data. */
- packet->packet_size = 0;
-
- /* Set endpoint as valid for transmitting new packet. */
- STM32_TOGGLE_EP(config->endpoint, EP_TX_MASK, EP_TX_VALID, 0);
-}
-
-/*
- * STM32 Platform: Returns the RX endpoint status
- *
- * @param config USB SPI config
- *
- * @returns Returns true when the RX endpoint has a packet.
- */
-static bool usb_spi_received_packet(struct usb_spi_config const *config)
-{
- return (STM32_USB_EP(config->endpoint) & EP_RX_MASK) != EP_RX_VALID;
-}
-
-/* STM32 Platform: Returns the TX endpoint status
- *
- * @param config USB SPI config
- *
- * @returns Returns true when the TX endpoint transmitted
- * the packet written.
- */
-static bool usb_spi_transmitted_packet(struct usb_spi_config const *config)
-{
- return (STM32_USB_EP(config->endpoint) & EP_TX_MASK) != EP_TX_VALID;
-}
-
-/* STM32 Platform: Handle interrupt for USB data received.
- *
- * @param config USB SPI config
- */
-void usb_spi_rx(struct usb_spi_config const *config)
-{
- /*
- * We need to set both the TX and RX endpoints to NAK to prevent
- * transfers. The protocol requires responses to follow a command, but
- * the USB host will request the next packet from the TX endpoint
- * before the USB SPI has updated the memory in the buffer. By setting
- * it to NAK in the ISR, it will not perform a transfer until the
- * next packet is ready.
- *
- * This has a side effect of disabling the endpoint interrupts until
- * they are set to valid or a USB reset events occurs.
- */
- STM32_TOGGLE_EP(config->endpoint, EP_TX_RX_MASK, EP_TX_RX_NAK, 0);
-
- hook_call_deferred(config->deferred, 0);
-}
-
-/*
- * STM32 Platform: Handle interrupt for USB data transmitted.
- *
- * @param config USB SPI config
- */
-void usb_spi_tx(struct usb_spi_config const *config)
-{
- STM32_TOGGLE_EP(config->endpoint, EP_TX_MASK, EP_TX_NAK, 0);
-
- hook_call_deferred(config->deferred, 0);
-}
-
-/*
- * STM32 Platform: Handle interrupt for USB events
- *
- * @param config USB SPI config
- * @param evt USB event
- */
-void usb_spi_event(struct usb_spi_config const *config, enum usb_ep_event evt)
-{
- int endpoint;
-
- if (evt != USB_EVENT_RESET)
- return;
-
- endpoint = config->endpoint;
-
- usb_spi_reset_interface(config);
-
- btable_ep[endpoint].tx_addr = usb_sram_addr(config->ep_tx_ram);
- btable_ep[endpoint].tx_count = 0;
-
- btable_ep[endpoint].rx_addr = usb_sram_addr(config->ep_rx_ram);
- btable_ep[endpoint].rx_count =
- 0x8000 | ((USB_MAX_PACKET_SIZE / 32 - 1) << 10);
-
- STM32_USB_EP(endpoint) = ((endpoint << 0) | /* Endpoint Addr*/
- (2 << 4) | /* TX NAK */
- (0 << 9) | /* Bulk EP */
- (3 << 12)); /* RX Valid */
-}
-
-/*
- * STM32 Platform: Handle control transfers.
- *
- * @param config USB SPI config
- * @param rx_buf Contains setup packet
- * @param tx_buf unused
- */
-int usb_spi_interface(struct usb_spi_config const *config,
- usb_uint *rx_buf,
- usb_uint *tx_buf)
-{
- struct usb_setup_packet setup;
-
- usb_read_setup_packet(rx_buf, &setup);
-
- if (setup.bmRequestType != (USB_DIR_OUT |
- USB_TYPE_VENDOR |
- USB_RECIP_INTERFACE))
- return 1;
-
- if (setup.wValue != 0 ||
- setup.wIndex != config->interface ||
- setup.wLength != 0)
- return 1;
-
- switch (setup.bRequest) {
- case USB_SPI_REQ_ENABLE:
- config->state->enabled_host = 1;
- break;
-
- case USB_SPI_REQ_DISABLE:
- config->state->enabled_host = 0;
- break;
-
- default: return 1;
- }
-
- /*
- * Our state has changed, call the deferred function to handle the
- * state change.
- */
- if (!(config->flags & USB_SPI_CONFIG_FLAGS_IGNORE_HOST_SIDE_ENABLE))
- hook_call_deferred(config->deferred, 0);
-
- usb_spi_reset_interface(config);
-
- btable_ep[0].tx_count = 0;
- STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, EP_STATUS_OUT);
- return 0;
-}