| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| #ifndef OPENTITAN_HW_DV_DPI_USBDPI_USB_TRANSFER_H_ |
| #define OPENTITAN_HW_DV_DPI_USBDPI_USB_TRANSFER_H_ |
| #include <stddef.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| |
| // USBDEV IP block supports up to 64-bytes/packet |
| #ifndef USBDEV_MAX_PACKET_SIZE |
| #define USBDEV_MAX_PACKET_SIZE 64U |
| #endif |
| |
| // Maximal length of a byte sequence to be transmitted/receive without |
| // interruption or pause (Start Of Frame, Setup packet, OUT Data packet |
| // and End Of Frame all back-to-back?) |
| #define USBDPI_MAX_DATA (3U + 3U + 1U + USBDEV_MAX_PACKET_SIZE + 2U + 1U) |
| |
| // Special value that denotes that this transfer does not include a data stage |
| #define USBDPI_NO_DATA_STAGE ((uint8_t)~0U) |
| |
| /** |
| * Forwards reference to usbpdi state context |
| */ |
| typedef struct usbdpi_ctx usbdpi_ctx_t; |
| |
| /** |
| * Description of a transfer over the USB |
| * |
| * A control transfer |
| * Setup stage - [ Data stage ] - Status stage |
| * A data transfer |
| * Setup stage - Data stage - [ Status stage ] |
| */ |
| typedef struct usbdpi_transfer usbdpi_transfer_t; |
| |
| struct usbdpi_transfer { |
| /** |
| * Received transfers are linked together in the order of receipt |
| */ |
| usbdpi_transfer_t *next; |
| /** |
| * Number of bytes to be transmitted/received |
| */ |
| uint8_t num_bytes; |
| /** |
| * Offset of the PID of the data stage (or USBDPI_NO_DATA_STAGE if none) |
| */ |
| uint8_t data_start; |
| /** |
| * Bytes being transferred (Note: this includes PID and CRCs; it is _not_ just |
| * the data field) |
| */ |
| uint8_t data[USBDPI_MAX_DATA]; |
| }; |
| |
| /** |
| * Set up all of the available transfer descriptors in a USB DPI context |
| * |
| * @param ctx USB DPI context |
| */ |
| void usb_transfer_setup(usbdpi_ctx_t *ctx); |
| |
| /** |
| * Allocate and initialize a transfer descriptor |
| * |
| * @param ctx USB DPI context |
| */ |
| usbdpi_transfer_t *transfer_alloc(usbdpi_ctx_t *ctx); |
| |
| /** |
| * Free a transfer descriptor and return it to the pool |
| * |
| * @param ctx USB DPI context |
| * @param transfer Transfer descriptor to be released |
| */ |
| void transfer_release(usbdpi_ctx_t *ctx, usbdpi_transfer_t *transfer); |
| |
| /** |
| * Initialize a transfer descriptor for use |
| * |
| * @param transfer Transfer descriptor to be initialized |
| */ |
| void transfer_init(usbdpi_transfer_t *transfer); |
| |
| /** |
| * Prepare and send a 'Start Of Frame' transfer descriptor |
| * |
| * @param ctx USB DPI context |
| * @param transfer Transfer descriptor |
| * @param frame Frame number to be sent |
| */ |
| void transfer_frame_start(usbdpi_ctx_t *ctx, usbdpi_transfer_t *transfer, |
| unsigned frame); |
| |
| /** |
| * Construct and send the setup stage of a control transfer |
| * |
| * @param ctx USB DPI context |
| * @param transfer Transfer descriptor |
| * @param bmRequestType Characteristics of USB device request |
| * @param bRequest Specific device request |
| * @param wValue Word-sized field that varies according to the request |
| * @param WIndex Typically used to pass an index or offset |
| * @param wLength Number of bytes to transfer if there is a Data stage |
| */ |
| void transfer_setup(usbdpi_ctx_t *ctx, usbdpi_transfer_t *transfer, |
| uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, |
| uint16_t wIndex, uint16_t wLength); |
| |
| /** |
| * Append a token packet to a transfer descriptor that is under construction |
| * |
| * @param transfer Transfer descriptor |
| * @param pid Packet IDentifier of token packet |
| * @param device Device address of recipient |
| * @param endpoint Endpoint number of recipient |
| */ |
| void transfer_token(usbdpi_transfer_t *transfer, uint8_t pid, uint8_t device, |
| uint8_t endpoint); |
| |
| /** |
| * Append a data stage to the given transfer descriptor, using the specified PID |
| * (DATA0|DATA1) and checking that there is sufficient space available |
| * (est_size) |
| * |
| * @param transfer Transfer descriptor under construction |
| * @param pid Packet IDentifier of data packet |
| * @param est_size Estimated size of data if known (or 0) |
| */ |
| uint8_t *transfer_data_start(usbdpi_transfer_t *transfer, uint8_t pid, |
| unsigned est_size); |
| |
| /** |
| * Conclude a data stage within a transfer, calculating and appending the CRC16 |
| * of the data field |
| * |
| * @param transfer Transfer descriptor under construction |
| * @param dp Pointer beyond the data field within the transfer |
| */ |
| void transfer_data_end(usbdpi_transfer_t *transfer, uint8_t *dp); |
| |
| /** |
| * Return access to the data field of a transfer descriptor |
| * |
| * @param transfer Transfer descriptor |
| * @return Pointer to the start of the data field or NULL |
| */ |
| inline uint8_t *transfer_data_field(usbdpi_transfer_t *transfer) { |
| assert(transfer); |
| if (transfer->data_start != USBDPI_NO_DATA_STAGE && |
| transfer->data_start + 1U < transfer->num_bytes) { |
| return &transfer->data[transfer->data_start + 1U]; |
| } |
| return NULL; |
| } |
| |
| /** |
| * Return DATAx PID of the data field of a transfer descriptor |
| * |
| * @param transfer Transfer descriptor |
| * @return USB_PID_DATA0|1 |
| */ |
| inline uint8_t transfer_data_pid(usbdpi_transfer_t *transfer) { |
| assert(transfer); |
| assert(transfer->data_start != USBDPI_NO_DATA_STAGE && |
| transfer->data_start + 1U < transfer->num_bytes); |
| return transfer->data[transfer->data_start]; |
| } |
| |
| /** |
| * Append some data to a transfer description |
| * |
| * @param transfer Transfer descriptor under construction |
| * @param dp Pointer to data bytes to be appended |
| * @param n Number of bytes |
| * @return true iff appended successfully |
| */ |
| bool transfer_append(usbdpi_transfer_t *transfer, const uint8_t *dp, size_t n); |
| |
| /** |
| * Prepare a transfer for transmission to the device, and get ready to transmit |
| * |
| * @param ctx USB DPI context |
| * @param transfer Transfer descriptor to be sent to device |
| */ |
| void transfer_send(usbdpi_ctx_t *ctx, usbdpi_transfer_t *transfer); |
| |
| /** |
| * Construct and prepare to send a Status response; |
| * |
| * Note: there is no requirement to call either transfer_init() or |
| * transfer_send() when using transfer_status() |
| * |
| * @param ctx USB DPI context |
| * @param transfer Transfer descriptor to be completed and sent |
| * @param pid Packet IDentifier of status packet |
| */ |
| void transfer_status(usbdpi_ctx_t *ctx, usbdpi_transfer_t *transfer, |
| uint8_t pid); |
| |
| /** |
| * Returns the total number of bytes to be transferred |
| * |
| * @param transfer Transfer descriptor |
| * @return Number of bytes |
| */ |
| |
| inline uint32_t transfer_length(const usbdpi_transfer_t *transfer) { |
| return transfer->num_bytes; |
| } |
| |
| /** |
| * Diagnostic utility function to dump out the contents of a transfer descriptor |
| * |
| * @param transfer Transfer descriptor |
| * @param out Stream to receive diagnostic output |
| */ |
| void transfer_dump(usbdpi_transfer_t *transfer, FILE *out); |
| |
| #endif // OPENTITAN_HW_DV_DPI_USBDPI_USB_TRANSFER_H_ |