summaryrefslogtreecommitdiff
path: root/chip/stm32/usb_dfu_runtime.c
diff options
context:
space:
mode:
authorBrian J. Nemec <bnemec@google.com>2022-02-04 13:01:40 -0800
committerCommit Bot <commit-bot@chromium.org>2022-02-11 06:22:45 +0000
commit5c9813df84e0d0794a92108262fc255854f6565c (patch)
tree182b197af47a30e73ea95779a652ae2d3a7272ee /chip/stm32/usb_dfu_runtime.c
parent59e9e0544ec4e449b11267053e5525d6de372a39 (diff)
downloadchrome-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.c91
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)