/* 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. */ #include "ccd_config.h" #include "common.h" #include "link_defs.h" #include "gpio.h" #include "registers.h" #include "spi.h" #include "spi_flash.h" #include "timer.h" #include "usb_descriptor.h" #include "usb_spi.h" #include "util.h" /* * This module implements support for SPI programming driven by the flashrom * utility over USB. * * Flashrom connects to the specific SPI USB endpoint and sends commands to * this driver to control the external SPI flash chip attached to the H1's SPI * host port. * * Some configuration actions might have to be performed before SPI * programming is possible (say asserting the AP reset, enabling a * multiplexer, etc.), these actions are not controlled/performed by this * module, it expects the 'H2<=>SPI flash' connection provisioned and the * flash chip ready to be programmed. * * The below protocol specification was copied from raiden_debug_spi.c in the * flashrom tree with addition of some clarifications. * * Note that this implementation imposes additional limits on SPI transactions * which include both read and write portions: the write size of such * transactions case can not exceed 60, the size of the payload of the first * USB packet carrying the transaction PDU. * * USB SPI Version 2: * * USB SPI version 2 adds support for larger SPI transfers which reduces * the number of USB packets transferred. This improves performance when * writing or reading large chunks of memory from a device. Larger * quantities are transferred in PDUs split into USB packets. * * A packet ID field is used to distinguish the different USB packet * types. Additional packets have been included to query the device for * its configuration allowing the interface to be used on platforms with * different SPI limitations. It includes validation and a packet to * recover from the situations where USB packets are lost. * * The device advertises the supported protocol version in the * bInterfaceProtocol field of the USB descriptor, this allows the USB SPI * hosts to be backwards compatible with version 1. * * * Example: USB SPI request with 128 byte write and 0 byte read. * * Packet #1 Host to Device: * packet id = USB_SPI_PKT_ID_CMD_TRANSFER_START * write count = 128 * read count = 0 * payload = First 58 bytes from the write buffer, * starting at byte 0 in the buffer * packet size = 64 bytes * * Packet #2 Host to Device: * packet id = USB_SPI_PKT_ID_CMD_TRANSFER_CONTINUE * data index = 58 * payload = Next 60 bytes from the write buffer, * starting at byte 58 in the buffer * packet size = 64 bytes * * Packet #3 Host to Device: * packet id = USB_SPI_PKT_ID_CMD_TRANSFER_CONTINUE * data index = 118 * payload = Next 10 bytes from the write buffer, * starting at byte 118 in the buffer * packet size = 14 bytes * * Packet #4 Device to Host: * packet id = USB_SPI_PKT_ID_RSP_TRANSFER_START * status code = status code from device * payload = 0 bytes * packet size = 4 bytes * * Example: USB SPI request with 2 byte write and 100 byte read. * * Packet #1 Host to Device: * packet id = USB_SPI_PKT_ID_CMD_TRANSFER_START * write count = 2 * read count = 100 * payload = The 2 byte write buffer * packet size = 8 bytes * * Packet #2 Device to Host: * packet id = USB_SPI_PKT_ID_RSP_TRANSFER_START * status code = status code from device * payload = First 60 bytes from the read buffer, * starting at byte 0 in the buffer * packet size = 64 bytes * * Packet #3 Device to Host: * packet id = USB_SPI_PKT_ID_RSP_TRANSFER_CONTINUE * data index = 60 * payload = Next 40 bytes from the read buffer, * starting at byte 60 in the buffer * packet size = 44 bytes * * * Message Packets: * * Note that all 16 bit fields are transferred in little endian mode. * * Command Start Packet (Host to Device): * * Start of the USB SPI command, contains the number of bytes to write * and read on SPI and up to the first 58 bytes of write payload. * Longer writes will use the continue packets with packet id * USB_SPI_PKT_ID_CMD_TRANSFER_CONTINUE to transmit the remaining data. * * The write part of the transaction is executed first; in case the * packet includes both read and write requests, the write portion is * required to fit into the first USB packet. * * +----------------+------------------+-----------------+---------------+ * | packet id : 2B | write count : 2B | read count : 2B | w.p. : <= 58B | * +----------------+------------------+-----------------+---------------+ * * packet id: 2 byte enum defined by packet_id_type * Valid values packet id = USB_SPI_PKT_ID_CMD_TRANSFER_START * * write count: 2 byte, zero based count of bytes to write * * read count: 2 byte, zero based count of bytes to read * UINT16_MAX indicates full duplex mode with a read count * equal to the write count. * * write payload: Up to 58 bytes of data to write to SPI, the total * length of all TX packets must match write count. * Due to data alignment constraints, this must be an * even number of bytes unless this is the final packet. * * * Response Start Packet (Device to Host): * * Start of the USB SPI response, contains the status code and up to * the first 60 bytes of read payload. Longer reads will use the * continue packets with packet id USB_SPI_PKT_ID_RSP_TRANSFER_CONTINUE * to transmit the remaining data. * * +----------------+------------------+-----------------------+ * | packet id : 2B | status code : 2B | read payload : <= 60B | * +----------------+------------------+-----------------------+ * * packet id: 2 byte enum defined by packet_id_type * Valid values packet id = USB_SPI_PKT_ID_RSP_TRANSFER_START * * status code: 2 byte status code * 0x0000: Success * 0x0001: SPI timeout * 0x0002: Busy, try again * This can happen if someone else has acquired the shared memory * buffer that the SPI driver uses as /dev/null * 0x0003: Write count invalid. The byte limit is platform specific * and is set during the configure USB SPI response. * 0x0004: Read count invalid. The byte limit is platform specific * and is set during the configure USB SPI response. * 0x0005: The SPI bridge is disabled. * 0x0006: The RX continue packet's data index is invalid. This * can indicate a USB transfer failure to the device. * 0x0007: The RX endpoint has received more data than write count. * This can indicate a USB transfer failure to the device. * 0x0008: An unexpected packet arrived that the device could not * process. * 0x0009: The device does not support full duplex mode. * 0x8000: Unknown error mask * The bottom 15 bits will contain the bottom 15 bits from the EC * error code. * * read payload: Up to 60 bytes of data read from SPI, the total * length of all RX packets must match read count * unless an error status was returned. Due to data * alignment constraints, this must be a even number * of bytes unless this is the final packet. * * * Continue Packet (Bidirectional): * * Continuation packet for the writes and read buffers. Both packets * follow the same format, a data index counts the number of bytes * previously transferred in the USB SPI transfer and a payload of bytes. * * +----------------+-----------------+-------------------------------+ * | packet id : 2B | data index : 2B | write / read payload : <= 60B | * +----------------+-----------------+-------------------------------+ * * packet id: 2 byte enum defined by packet_id_type * The packet id has 2 values depending on direction: * packet id = USB_SPI_PKT_ID_CMD_TRANSFER_CONTINUE * indicates the packet is being transmitted from the host * to the device and contains SPI write payload. * packet id = USB_SPI_PKT_ID_RSP_TRANSFER_CONTINUE * indicates the packet is being transmitted from the device * to the host and contains SPI read payload. * * data index: The data index indicates the number of bytes in the * read or write buffers that have already been transmitted. * It is used to validate that no packets have been dropped * and that the prior packets have been correctly decoded. * This value corresponds to the offset bytes in the buffer * to start copying the payload into. * * read and write payload: * Contains up to 60 bytes of payload data to transfer to * the SPI write buffer or from the SPI read buffer. * * * Command Get Configuration Packet (Host to Device): * * Query the device to request its USB SPI configuration indicating * the number of bytes it can write and read. * * +----------------+ * | packet id : 2B | * +----------------+ * * packet id: 2 byte enum USB_SPI_PKT_ID_CMD_GET_USB_SPI_CONFIG * * Response Configuration Packet (Device to Host): * * Response packet form the device to report the maximum write and * read size supported by the device. * * +----------------+----------------+---------------+----------------+ * | packet id : 2B | max write : 2B | max read : 2B | feature bitmap | * +----------------+----------------+---------------+----------------+ * * packet id: 2 byte enum USB_SPI_PKT_ID_RSP_USB_SPI_CONFIG * * max write count: 2 byte count of the maximum number of bytes * the device can write to SPI in one transaction. * * max read count: 2 byte count of the maximum number of bytes * the device can read from SPI in one transaction. * * feature bitmap: Bitmap of supported features. * BIT(0): Full duplex SPI mode is supported * BIT(1:15): Reserved for future use * * Command Restart Response Packet (Host to Device): * * Command to restart the response transfer from the device. This enables * the host to recover from a lost packet when reading the response * without restarting the SPI transfer. * * +----------------+ * | packet id : 2B | * +----------------+ * * packet id: 2 byte enum USB_SPI_PKT_ID_CMD_RESTART_RESPONSE * * USB Error Codes: * * send_command return codes have the following format: * * 0x00000: Status code success. * 0x00001-0x0FFFF: Error code returned by the USB SPI device. * 0x10001-0x1FFFF: Error code returned by the USB SPI host. * 0x20001-0x20063 Lower bits store the positive value representation * of the libusb_error enum. See the libusb documentation: * http://libusb.sourceforge.net/api-1.0/group__misc.html * */ #define CPUTS(outstr) cputs(CC_USB, outstr) #define CPRINTS(format, args...) cprints(CC_USB, format, ## args) 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); } } static uint16_t usb_spi_read_packet(struct usb_spi_config const *config) { return QUEUE_REMOVE_UNITS(config->consumer.queue, config->buffer, queue_count(config->consumer.queue)); } static void usb_spi_write_packet(struct usb_spi_config const *config, uint8_t count) { /* * Experiments show that while reading a 16M flash time spent waiting * is less than 30 ms, which is negligible in this case, as the AP is * held in reset. */ while (queue_space(config->tx_queue) < count) msleep(1); QUEUE_ADD_UNITS(config->tx_queue, config->buffer, count); } enum packet_id_type { /* Request USB SPI configuration data from device. */ USB_SPI_PKT_ID_CMD_GET_USB_SPI_CONFIG = 0, /* USB SPI configuration data from device. */ USB_SPI_PKT_ID_RSP_USB_SPI_CONFIG = 1, /* * Start a USB SPI transfer specifying number of bytes to write, * read and deliver first packet of data to write. */ USB_SPI_PKT_ID_CMD_TRANSFER_START = 2, /* Additional packets containing write payload. */ USB_SPI_PKT_ID_CMD_TRANSFER_CONTINUE = 3, /* * Request the device restart the response enabling us to recover * from packet loss without another SPI transfer. */ USB_SPI_PKT_ID_CMD_RESTART_RESPONSE = 4, /* * First packet of USB SPI response with the status code * and read payload if it was successful. */ USB_SPI_PKT_ID_RSP_TRANSFER_START = 5, /* Additional packets containing read payload. */ USB_SPI_PKT_ID_RSP_TRANSFER_CONTINUE = 6, /* Inform the device that transfer is over. */ USB_SPI_PKT_ID_CMD_HOST_DONE = 7, /* Inform the host that processing is finished. */ USB_SPI_PKT_ID_RSP_DEVICE_DONE = 8, }; enum feature_bitmap { /* Indicates the platform supports full duplex mode. */ USB_SPI_FEATURE_FULL_DUPLEX_SUPPORTED = BIT(0) }; /* Helper structures defining various PDU headers. */ struct raiden_response_hdr { uint16_t packet_id; uint16_t value; /* Either offset into the PDU or error code. */ }; struct raiden_cmd_start_hdr { uint16_t packet_id; uint16_t write_count; uint16_t read_count; }; struct raiden_cmd_continue_hdr { uint16_t packet_id; uint16_t offset; }; union raiden_cmd_hdr { struct raiden_cmd_start_hdr s; struct raiden_cmd_continue_hdr c; }; #define START_PAYLOAD_SIZE \ (USB_MAX_PACKET_SIZE - sizeof(struct raiden_cmd_start_hdr)) #define CONT_PAYLOAD_SIZE \ (USB_MAX_PACKET_SIZE - sizeof(struct raiden_cmd_continue_hdr)) #define RESP_PAYLOAD_SIZE \ (USB_MAX_PACKET_SIZE - sizeof(struct raiden_response_hdr)) /* * Hardcoded values used to communicate to the host maximum sizes of read and * write transactions. */ /* * Six bytes header, one byte command, up to four byte addr, 256 bytes data * page and then some in case there is a chip which uses a multibyte command. */ #define USB_SPI_MAX_WRITE_COUNT 270 /* * Flashrom deducts 5 from this value, remaining 2040 bytes size results in 34 * USB packets of 4 byte header and 60 bytes data. */ #define USB_SPI_MAX_READ_COUNT (5 + 34 * RESP_PAYLOAD_SIZE) /* Hadrdcoded response to the config request packet. */ static const struct { uint16_t rsp_id; uint16_t max_write; uint16_t max_read; uint16_t features; } config_rsp = { USB_SPI_PKT_ID_RSP_USB_SPI_CONFIG, USB_SPI_MAX_WRITE_COUNT, USB_SPI_MAX_READ_COUNT, 0 }; /* * Prepare an error message to be sent back to the host and switch to * RAIDEN_IDLE state. * * The return value is the number of bytes to send to the controller. */ static uint8_t report_error(void *packet, uint16_t error, struct usb_spi_state *state) { /* Packet is guaranteed to be 2 bytes aligned. */ struct raiden_response_hdr *rsp = (struct raiden_response_hdr *)packet; rsp->packet_id = USB_SPI_PKT_ID_RSP_TRANSFER_START; rsp->value = error; state->raiden_state = RAIDEN_IDLE; return sizeof(*rsp); } /* Return length of the last response packet to send back to the host. */ static uint8_t process_raiden_packet(const struct usb_spi_config *config, size_t count) { /* Buffer is guaranteed to be 2 bytes aligned. */ union raiden_cmd_hdr *packet = (union raiden_cmd_hdr *)config->buffer; struct raiden_response_hdr *rsp = (struct raiden_response_hdr *)config->buffer; uint16_t total_read_count; uint16_t read_so_far; uint16_t this_read_count = 0; uint16_t this_write_count = 0; bool last_sub_transaction; uint16_t res; uint16_t packet_id; struct usb_spi_state *state = config->state; if (count < sizeof(packet->s.packet_id)) return report_error(config->buffer, USB_SPI_UNKNOWN_ERROR, state); packet_id = packet->s.packet_id; switch (state->raiden_state) { case RAIDEN_IDLE: if ((packet_id == USB_SPI_PKT_ID_CMD_GET_USB_SPI_CONFIG) && (count == sizeof(uint16_t))) { memcpy(config->buffer, &config_rsp, sizeof(config_rsp)); return sizeof(config_rsp); } if ((packet_id != USB_SPI_PKT_ID_CMD_TRANSFER_START) || (count < sizeof(struct raiden_cmd_start_hdr))) return report_error(config->buffer, USB_SPI_RUNT_PACKET, state); /* This is request to start a new transaction. */ state->total_write_count = packet->s.write_count; total_read_count = packet->s.read_count; /* Some basic validity checks. */ if (total_read_count > config_rsp.max_read) return report_error(config->buffer, USB_SPI_READ_COUNT_INVALID, state); if (state->total_write_count > config_rsp.max_write) return report_error(config->buffer, USB_SPI_WRITE_COUNT_INVALID, state); /* * If write count fits into one USB packet, the size of packet * must match. */ if ((state->total_write_count <= (USB_MAX_PACKET_SIZE - sizeof(struct raiden_cmd_start_hdr))) && (state->total_write_count != (count - sizeof(struct raiden_cmd_start_hdr)))) return report_error(config->buffer, USB_SPI_WRITE_COUNT_INVALID, state); /* * Transactions with write count exceeding one USB packet AND * requiring a read are not supported. */ if (total_read_count && (state->total_write_count > START_PAYLOAD_SIZE)) return report_error(config->buffer, USB_SPI_WRITE_COUNT_INVALID, state); read_so_far = 0; state->wrote_so_far = 0; if (state->total_write_count > START_PAYLOAD_SIZE) this_write_count = START_PAYLOAD_SIZE; else this_write_count = state->total_write_count; while (this_write_count || (read_so_far != total_read_count)) { this_read_count = total_read_count - read_so_far; /* * Need to decide if CS needs to be deasserted in this * iteration. It would be the case if both final read * and write counts fit into USB packet. */ if ((this_read_count > RESP_PAYLOAD_SIZE) || (state->total_write_count > START_PAYLOAD_SIZE)) { last_sub_transaction = false; /* Limit read count by USB packet capacity. */ if (this_read_count > RESP_PAYLOAD_SIZE) this_read_count = RESP_PAYLOAD_SIZE; } else { last_sub_transaction = true; } res = usb_spi_map_error(spi_sub_transaction( SPI_FLASH_DEVICE, config->buffer + sizeof(struct raiden_cmd_start_hdr), this_write_count, config->buffer + sizeof(struct raiden_response_hdr), this_read_count, last_sub_transaction)); if (res) { rsp->value = res; rsp->packet_id = USB_SPI_PKT_ID_RSP_TRANSFER_START; return sizeof(*rsp); } rsp->packet_id = read_so_far ? USB_SPI_PKT_ID_RSP_TRANSFER_CONTINUE : USB_SPI_PKT_ID_RSP_TRANSFER_START; rsp->value = read_so_far; state->wrote_so_far += this_write_count; read_so_far += this_read_count; if (state->total_write_count > state->wrote_so_far) { state->raiden_state = RAIDEN_WRITING; return 0; } if (last_sub_transaction) break; usb_spi_write_packet(config, this_read_count + sizeof(*rsp)); /* * Make sure this does not keep the loop going, we * wrote all there was to write. */ this_write_count = 0; } if (this_read_count) return this_read_count + sizeof(*rsp); if (state->total_write_count && (state->total_write_count == this_write_count)) return sizeof(*rsp); return 0; case RAIDEN_WRITING: if ((packet_id != USB_SPI_PKT_ID_CMD_TRANSFER_CONTINUE) || (count <= sizeof(struct raiden_cmd_continue_hdr))) return report_error(config->buffer, USB_SPI_RX_UNEXPECTED_PACKET, state); if (packet->c.offset != state->wrote_so_far) return report_error(config->buffer, USB_SPI_RX_UNEXPECTED_PACKET, state); this_write_count = count - sizeof(struct raiden_cmd_continue_hdr); /* * This is the last sub transaction if the remainder of data * to write fits into USB packet, CS will have to be * deasserted. */ last_sub_transaction = (this_write_count + state->wrote_so_far) == state->total_write_count; res = usb_spi_map_error(spi_sub_transaction( SPI_FLASH_DEVICE, config->buffer + sizeof(struct raiden_response_hdr), this_write_count, config->buffer, 0, last_sub_transaction)); if (res) { rsp->value = res; rsp->packet_id = USB_SPI_PKT_ID_RSP_TRANSFER_START; state->raiden_state = RAIDEN_IDLE; return sizeof(*rsp); } if (last_sub_transaction) { state->raiden_state = RAIDEN_IDLE; rsp->value = 0; rsp->packet_id = USB_SPI_PKT_ID_RSP_TRANSFER_START; return sizeof(*rsp); } state->wrote_so_far += this_write_count; return 0; } return 0; } void usb_spi_deferred(struct usb_spi_config const *config) { uint16_t count; int rv = EC_SUCCESS; /* * If our overall enabled state has changed we call the board specific * enable or disable routines and save our new state. */ int enabled = !!(config->state->enabled_host & config->state->enabled_device); if (enabled ^ config->state->enabled) { if (enabled) rv = usb_spi_board_enable(config->state->enabled_host); else usb_spi_board_disable(); /* Only update our state if we were successful. */ if (rv == EC_SUCCESS) config->state->enabled = enabled; } /* * And if there is a USB packet waiting we process it and generate a * response. */ count = usb_spi_read_packet(config); if (count == 0) return; if (!config->state->enabled || usb_spi_shortcut_active()) { struct raiden_response_hdr rsp_hdr = { USB_SPI_PKT_ID_RSP_TRANSFER_START, USB_SPI_DISABLED }; memcpy(config->buffer, &rsp_hdr, sizeof(rsp_hdr)); usb_spi_write_packet(config, sizeof(rsp_hdr)); return; } /* * Call the protocol handler and send back the last message generated * by the handler. */ usb_spi_write_packet(config, process_raiden_packet(config, count)); } static void usb_spi_written(struct consumer const *consumer, size_t count) { struct usb_spi_config const *config = DOWNCAST(consumer, struct usb_spi_config, consumer); hook_call_deferred(config->deferred, 0); } struct consumer_ops const usb_spi_consumer_ops = { .written = usb_spi_written, }; void usb_spi_enable(struct usb_spi_config const *config, int enabled) { config->state->enabled_device = 0; if (enabled) { #ifdef CONFIG_CASE_CLOSED_DEBUG_V1 if (ccd_is_cap_enabled(CCD_CAP_AP_FLASH)) config->state->enabled_device |= USB_SPI_AP; if (ccd_is_cap_enabled(CCD_CAP_EC_FLASH)) config->state->enabled_device |= USB_SPI_EC; #else config->state->enabled_device = USB_SPI_ALL; #endif } hook_call_deferred(config->deferred, 0); }