diff options
author | Brian J. Nemec <bnemec@google.com> | 2022-02-04 13:01:40 -0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2022-02-11 06:22:45 +0000 |
commit | 5c9813df84e0d0794a92108262fc255854f6565c (patch) | |
tree | 182b197af47a30e73ea95779a652ae2d3a7272ee /chip/stm32/usb_dfu_runtime.c | |
parent | 59e9e0544ec4e449b11267053e5525d6de372a39 (diff) | |
download | chrome-ec-5c9813df84e0d0794a92108262fc255854f6565c.tar.gz |
stm32: Add the DFU Runtime identifiers
Adds a DFU Runtime identifier and a DFU bootmanager to control the
switch between the DFU and main application region.
The DFU runtime identifier operates on the main application in the RW
region. A DFU host recognizes the interface and can send commands to
switch the firmware into DFU mode.
BRANCH=servo
BUG=b:217955677
TEST=Enabled the DFU configuration on Servo_v4 with CONFIG_DFU_RUNTIME
TEST='sudo dfu-util -l' Verified the dfu-util recognizes the
DFU runtime device.
Signed-off-by: Brian Nemec <bnemec@chromium.org>
Change-Id: I0e02b7cb35a7c594f169c56a96f965e5d87e3cfb
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3441173
Tested-by: Brian Nemec <bnemec@google.com>
Reviewed-by: Sam Hurst <shurst@google.com>
Commit-Queue: Brian Nemec <bnemec@google.com>
Diffstat (limited to 'chip/stm32/usb_dfu_runtime.c')
-rw-r--r-- | chip/stm32/usb_dfu_runtime.c | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/chip/stm32/usb_dfu_runtime.c b/chip/stm32/usb_dfu_runtime.c new file mode 100644 index 0000000000..b902f32af2 --- /dev/null +++ b/chip/stm32/usb_dfu_runtime.c @@ -0,0 +1,91 @@ +/* Copyright 2022 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 "registers.h" +#include "usb_descriptor.h" +#include "usb_dfu_runtime.h" +#include "usb_hw.h" + +/* DFU Run-Time Descriptor Set. */ +const struct usb_interface_descriptor USB_IFACE_DESC(USB_IFACE_DFU) = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = USB_IFACE_DFU, + .bAlternateSetting = 0, + .bNumEndpoints = 0, + .bInterfaceClass = USB_CLASS_APP_SPEC, + .bInterfaceSubClass = USB_DFU_RUNTIME_SUBCLASS, + .bInterfaceProtocol = USB_DFU_RUNTIME_PROTOCOL, + .iInterface = USB_STR_DFU_NAME, +}; + +/* DFU Functional Descriptor. */ +const struct usb_runtime_dfu_functional_desc USB_CUSTOM_DESC_VAR(USB_IFACE_DFU, + dfu, dfu_func_desc) = { + .bLength = USB_DFU_RUNTIME_DESC_SIZE, + .bDescriptorType = USB_DFU_RUNTIME_DESC_FUNCTIONAL, + .bmAttributes = USB_DFU_RUNTIME_DESC_ATTRS, + .wDetachTimeOut = USB_DFU_RUNTIME_DESC_DETACH_TIMEOUT, + .wTransferSize = USB_DFU_RUNTIME_DESC_TRANSFER_SIZE, + .bcdDFUVersion = USB_DFU_RUNTIME_DESC_DFU_VERSION, +}; + +static int dfu_runtime_request(usb_uint *ep0_buf_rx, usb_uint *ep0_buf_tx) +{ + struct usb_setup_packet packet; + + usb_read_setup_packet(ep0_buf_rx, &packet); + btable_ep[0].tx_count = 0; + if ((packet.bmRequestType == + (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_INTERFACE)) && + (packet.bRequest == USB_REQ_SET_INTERFACE)) { + /* ACK the change alternative mode request. */ + + STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, 0); + return 0; + } else if ((packet.bmRequestType == + (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) && + (packet.bRequest == USB_DFU_RUNTIME_REQ_DETACH)) { + /* Host is requesting a jump from application to DFU mode. */ + + STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, 0); + return 0; + } else if (packet.bmRequestType == + (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) { + if (packet.bRequest == USB_DFU_RUNTIME_REQ_GET_STATUS) { + /* Return the Get Status response. */ + + struct usb_runtime_dfu_get_status_resp response = { + .bStatus = USB_DFU_RUNTIME_STATUS_OK, + .bState = USB_DFU_RUNTIME_STATE_APP_IDLE, + }; + + memcpy_to_usbram((void *) usb_sram_addr(ep0_buf_tx), + &response, sizeof(response)); + btable_ep[0].tx_count = sizeof(response); + STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, 0); + return 0; + } + if (packet.bRequest == USB_DFU_RUNTIME_REQ_GET_STATE) { + /* Return the Get State response. */ + + struct usb_runtime_dfu_get_state_resp response = { + .bState = USB_DFU_RUNTIME_STATE_APP_IDLE, + }; + + memcpy_to_usbram((void *) usb_sram_addr(ep0_buf_tx), + &response, sizeof(response)); + btable_ep[0].tx_count = sizeof(response); + STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, 0); + return 0; + } + } + /* Return a stall response for any unhandled packets. */ + + STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_RX_VALID | EP_TX_STALL, 0); + return 0; +} + +USB_DECLARE_IFACE(USB_IFACE_DFU, dfu_runtime_request) |