[sw/usb] Rebase USB software stack atop DIFs

Also fix up tests to use the DIFs.

Signed-off-by: Alexander Williams <awill@google.com>
diff --git a/sw/device/examples/hello_usbdev/BUILD b/sw/device/examples/hello_usbdev/BUILD
index 1f51e33..fe00326 100644
--- a/sw/device/examples/hello_usbdev/BUILD
+++ b/sw/device/examples/hello_usbdev/BUILD
@@ -27,8 +27,6 @@
     deps = [
         "//hw/top_earlgrey/sw/autogen:top_earlgrey",
         "//sw/device/examples:demos",
-        "//sw/device/lib:usb",
-        "//sw/device/lib:usb_simpleserial",
         "//sw/device/lib/arch:device",
         "//sw/device/lib/crt",
         "//sw/device/lib/dif:gpio",
@@ -39,6 +37,8 @@
         "//sw/device/lib/runtime:log",
         "//sw/device/lib/runtime:print",
         "//sw/device/lib/testing:pinmux_testutils",
+        "//sw/device/lib/testing:usb_testutils",
+        "//sw/device/lib/testing:usb_testutils_simpleserial",
         "//sw/device/lib/testing/test_framework:check",
         "//sw/device/lib/testing/test_framework:ottf_start",
         "//sw/device/lib/testing/test_framework:ottf_test_config",
diff --git a/sw/device/examples/hello_usbdev/hello_usbdev.c b/sw/device/examples/hello_usbdev/hello_usbdev.c
index c6351a6..9c29c8a 100644
--- a/sw/device/examples/hello_usbdev/hello_usbdev.c
+++ b/sw/device/examples/hello_usbdev/hello_usbdev.c
@@ -17,9 +17,9 @@
 #include "sw/device/lib/testing/pinmux_testutils.h"
 #include "sw/device/lib/testing/test_framework/check.h"
 #include "sw/device/lib/testing/test_framework/ottf_test_config.h"
-#include "sw/device/lib/usb_controlep.h"
-#include "sw/device/lib/usb_simpleserial.h"
-#include "sw/device/lib/usbdev.h"
+#include "sw/device/lib/testing/usb_testutils.h"
+#include "sw/device/lib/testing/usb_testutils_controlep.h"
+#include "sw/device/lib/testing/usb_testutils_simpleserial.h"
 
 #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"  // Generated.
 
@@ -49,10 +49,10 @@
 /**
  * USB device context types.
  */
-static usbdev_ctx_t usbdev;
-static usb_controlep_ctx_t usbdev_control;
-static usb_ss_ctx_t simple_serial0;
-static usb_ss_ctx_t simple_serial1;
+static usb_testutils_ctx_t usbdev;
+static usb_testutils_controlep_ctx_t usbdev_control;
+static usb_testutils_ss_ctx_t simple_serial0;
+static usb_testutils_ss_ctx_t simple_serial1;
 
 /**
  * Makes `c` into a printable character, replacing it with `replacement`
@@ -101,9 +101,9 @@
  * @param string Zero terminated string to send.
  * @param ss_ctx Pointer to simple string endpoint context to send through.
  */
-static void usb_send_str(const char *string, usb_ss_ctx_t *ss_ctx) {
+static void usb_send_str(const char *string, usb_testutils_ss_ctx_t *ss_ctx) {
   for (int i = 0; string[i] != 0; ++i) {
-    usb_simpleserial_send_byte(ss_ctx, string[i]);
+    usb_testutils_simpleserial_send_byte(ss_ctx, string[i]);
   }
 }
 
@@ -181,20 +181,23 @@
   CHECK_DIF_OK(dif_spi_device_send(&spi, "SPI!", 4, /*bytes_sent=*/NULL));
 
   // The TI phy always uses a differential TX interface
-  usbdev_init(&usbdev, pinflip, differential_xcvr, differential_xcvr && !uphy);
+  usb_testutils_init(&usbdev, pinflip, differential_xcvr,
+                     differential_xcvr && !uphy);
 
-  usb_controlep_init(&usbdev_control, &usbdev, 0, config_descriptors,
-                     sizeof(config_descriptors));
-  while (usbdev_control.device_state != kUsbDeviceConfigured) {
-    usbdev_poll(&usbdev);
+  usb_testutils_controlep_init(&usbdev_control, &usbdev, 0, config_descriptors,
+                               sizeof(config_descriptors));
+  while (usbdev_control.device_state != kUsbTestutilsDeviceConfigured) {
+    usb_testutils_poll(&usbdev);
   }
-  usb_simpleserial_init(&simple_serial0, &usbdev, 1, usb_receipt_callback_0);
-  usb_simpleserial_init(&simple_serial1, &usbdev, 2, usb_receipt_callback_1);
+  usb_testutils_simpleserial_init(&simple_serial0, &usbdev, 1,
+                                  usb_receipt_callback_0);
+  usb_testutils_simpleserial_init(&simple_serial1, &usbdev, 2,
+                                  usb_receipt_callback_1);
 
   bool say_hello = true;
   bool pass_signaled = false;
   while (true) {
-    usbdev_poll(&usbdev);
+    usb_testutils_poll(&usbdev);
 
     gpio_state = demo_gpio_to_log_echo(&gpio, gpio_state);
     demo_spi_to_log_echo(&spi);
@@ -218,8 +221,8 @@
         uint32_t usb_stat = REG32(USBDEV_BASE_ADDR + USBDEV_USBSTAT_REG_OFFSET);
         LOG_INFO("I%04x-%08x", usb_irq_state, usb_stat);
       } else {
-        usb_simpleserial_send_byte(&simple_serial0, rcv_char);
-        usb_simpleserial_send_byte(&simple_serial1, rcv_char + 1);
+        usb_testutils_simpleserial_send_byte(&simple_serial0, rcv_char);
+        usb_testutils_simpleserial_send_byte(&simple_serial1, rcv_char + 1);
       }
     }
     if (say_hello && usb_chars_recved_total > 2) {
diff --git a/sw/device/lib/BUILD b/sw/device/lib/BUILD
index 8e69231..6646e50 100644
--- a/sw/device/lib/BUILD
+++ b/sw/device/lib/BUILD
@@ -41,29 +41,3 @@
         "//sw/device/lib/base:csr",
     ],
 )
-
-cc_library(
-    name = "usb",
-    srcs = [
-        "usb_controlep.c",
-        "usbdev.c",
-    ],
-    hdrs = [
-        "usb_consts.h",
-        "usb_controlep.h",
-        "usbdev.h",
-    ],
-    target_compatible_with = [OPENTITAN_CPU],
-    deps = [
-        "//hw/ip/usbdev/data:usbdev_regs",
-        "//hw/top_earlgrey/sw/autogen:top_earlgrey",
-    ],
-)
-
-cc_library(
-    name = "usb_simpleserial",
-    srcs = ["usb_simpleserial.c"],
-    hdrs = ["usb_simpleserial.h"],
-    target_compatible_with = [OPENTITAN_CPU],
-    deps = [":usb"],
-)
diff --git a/sw/device/lib/dif/dif_usbdev.c b/sw/device/lib/dif/dif_usbdev.c
index 625f0c7..3e5105f 100644
--- a/sw/device/lib/dif/dif_usbdev.c
+++ b/sw/device/lib/dif/dif_usbdev.c
@@ -576,7 +576,7 @@
   if (usbdev == NULL || buffer_pool == NULL || !is_valid_endpoint(endpoint)) {
     return kDifBadArg;
   }
-  // Get the configin register offset and bit index of the endpoint
+  // Get the configin register offset and bit index of the endpoint.
   uint32_t config_in_reg_offset =
       kEndpointHwInfos[endpoint].config_in_reg_offset;
   uint32_t config_in_reg_val =
@@ -586,10 +586,10 @@
 
   mmio_region_write32(usbdev->base_addr, config_in_reg_offset,
                       1u << USBDEV_CONFIGIN_0_PEND_0_BIT);
-  // Clear IN_SENT bit (rw1c)
+  // Clear IN_SENT bit (rw1c).
   mmio_region_write32(usbdev->base_addr, USBDEV_IN_SENT_REG_OFFSET,
                       1u << endpoint);
-  // Return the buffer back to the free buffer pool
+  // Return the buffer back to the free buffer pool.
   if (!buffer_pool_add(buffer_pool, buffer)) {
     return kDifError;
   }
@@ -603,29 +603,29 @@
     return kDifBadArg;
   }
 
-  // Get the configin register offset and bit index of the endpoint
+  // Get the configin register offset and bit index of the endpoint.
   uint32_t config_in_reg_offset =
       kEndpointHwInfos[endpoint].config_in_reg_offset;
   uint8_t endpoint_bit_index = kEndpointHwInfos[endpoint].bit_index;
 
-  // Read the configin register
+  // Read the configin register.
   uint32_t config_in_val =
       mmio_region_read32(usbdev->base_addr, config_in_reg_offset);
 
-  // Check the status of the packet
+  // Check the status of the packet.
   if (bitfield_bit32_read(config_in_val, USBDEV_CONFIGIN_0_RDY_0_BIT)) {
-    // Packet is marked as ready to be sent and pending transmission
+    // Packet is marked as ready to be sent and pending transmission.
     *status = kDifUsbdevTxStatusPending;
   } else if (bitfield_bit32_read(mmio_region_read32(usbdev->base_addr,
                                                     USBDEV_IN_SENT_REG_OFFSET),
                                  endpoint_bit_index)) {
-    // Packet was sent successfully
+    // Packet was sent successfully.
     *status = kDifUsbdevTxStatusSent;
   } else if (bitfield_bit32_read(config_in_val, USBDEV_CONFIGIN_0_PEND_0_BIT)) {
-    // Canceled due to an IN SETUP packet or link reset
+    // Canceled due to an IN SETUP packet or link reset.
     *status = kDifUsbdevTxStatusCancelled;
   } else {
-    // No packet has been queued for this endpoint
+    // No packet has been queued for this endpoint.
     *status = kDifUsbdevTxStatusNoPacket;
   }
 
diff --git a/sw/device/lib/testing/BUILD b/sw/device/lib/testing/BUILD
index 1bd2774..acb05ec 100644
--- a/sw/device/lib/testing/BUILD
+++ b/sw/device/lib/testing/BUILD
@@ -256,3 +256,32 @@
         "//sw/device/lib/testing/test_framework:check",
     ],
 )
+
+cc_library(
+    name = "usb_testutils",
+    srcs = [
+        "usb_testutils.c",
+        "usb_testutils_controlep.c",
+    ],
+    hdrs = [
+        "usb_testutils.h",
+        "usb_testutils_controlep.h",
+    ],
+    target_compatible_with = [OPENTITAN_CPU],
+    deps = [
+        "//hw/top_earlgrey/sw/autogen:top_earlgrey",
+        "//sw/device/lib/dif:usbdev",
+        "//sw/device/lib/testing/test_framework:check",
+    ],
+)
+
+cc_library(
+    name = "usb_testutils_simpleserial",
+    srcs = ["usb_testutils_simpleserial.c"],
+    hdrs = ["usb_testutils_simpleserial.h"],
+    target_compatible_with = [OPENTITAN_CPU],
+    deps = [
+        ":usb_testutils",
+        "//sw/device/lib/testing/test_framework:check",
+    ],
+)
diff --git a/sw/device/lib/testing/usb_testutils.c b/sw/device/lib/testing/usb_testutils.c
new file mode 100644
index 0000000..343a588
--- /dev/null
+++ b/sw/device/lib/testing/usb_testutils.c
@@ -0,0 +1,191 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include "sw/device/lib/testing/usb_testutils.h"
+
+#include "sw/device/lib/dif/dif_usbdev.h"
+#include "sw/device/lib/testing/test_framework/check.h"
+
+#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
+
+#define USBDEV_BASE_ADDR TOP_EARLGREY_USBDEV_BASE_ADDR
+
+static dif_usbdev_t usbdev;
+static dif_usbdev_buffer_pool_t buffer_pool;
+
+void usb_testutils_poll(usb_testutils_ctx_t *ctx) {
+  uint32_t istate;
+  CHECK_DIF_OK(dif_usbdev_irq_get_state(ctx->dev, &istate));
+
+  // Do this first to keep things going
+  CHECK_DIF_OK(dif_usbdev_fill_available_fifo(ctx->dev, ctx->buffer_pool));
+
+  // Process IN completions first so we get the fact that send completed
+  // before processing a response
+  if (istate & (1u << kDifUsbdevIrqPktSent)) {
+    uint16_t sentep;
+    CHECK_DIF_OK(dif_usbdev_get_tx_sent(ctx->dev, &sentep));
+    TRC_C('a' + sentep);
+    for (int ep = 0; ep < USBDEV_NUM_ENDPOINTS; ep++) {
+      if (sentep & (1 << ep)) {
+        // Free up the buffer and optionally callback
+        CHECK_DIF_OK(
+            dif_usbdev_clear_tx_status(ctx->dev, ctx->buffer_pool, ep));
+        if (ctx->tx_done_callback[ep]) {
+          ctx->tx_done_callback[ep](ctx->ep_ctx[ep]);
+        }
+      }
+    }
+  }
+
+  if (istate & (1u << kDifUsbdevIrqPktReceived)) {
+    while (true) {
+      bool is_empty;
+      CHECK_DIF_OK(dif_usbdev_status_get_rx_fifo_empty(ctx->dev, &is_empty));
+      if (is_empty) {
+        break;
+      }
+
+      dif_usbdev_rx_packet_info_t packet_info;
+      dif_usbdev_buffer_t buffer;
+      CHECK_DIF_OK(dif_usbdev_recv(ctx->dev, &packet_info, &buffer));
+
+      uint8_t endpoint = packet_info.endpoint;
+      if (ctx->rx_callback[endpoint]) {
+        ctx->rx_callback[endpoint](ctx->ep_ctx[endpoint], packet_info, buffer);
+      } else {
+        TRC_S("USB: unexpected RX ");
+        TRC_I(rxinfo, 24);
+        CHECK_DIF_OK(
+            dif_usbdev_buffer_return(ctx->dev, ctx->buffer_pool, &buffer));
+      }
+    }
+  }
+  if (istate & (1u << kDifUsbdevIrqLinkReset)) {
+    TRC_S("USB: Bus reset");
+    // Link reset
+    for (int ep = 0; ep < USBDEV_NUM_ENDPOINTS; ep++) {
+      if (ctx->reset[ep]) {
+        ctx->reset[ep](ctx->ep_ctx[ep]);
+      }
+    }
+  }
+  if (istate &
+      ~((1u << kDifUsbdevIrqLinkReset) | (1u << kDifUsbdevIrqPktReceived) |
+        (1u << kDifUsbdevIrqPktSent))) {
+    TRC_C('I');
+    TRC_I(istate, 12);
+    TRC_C(' ');
+  }
+  // Clear the interupts
+  CHECK_DIF_OK(dif_usbdev_irq_acknowledge_all(ctx->dev));
+
+  // TODO - clean this up
+  // Frame ticks every 1ms, use to flush data every 16ms
+  // (faster in DPI but this seems to work ok)
+  // At reset frame count is 0, compare to 1 so no calls before SOF received
+  uint16_t usbframe;
+  CHECK_DIF_OK(dif_usbdev_status_get_frame(ctx->dev, &usbframe));
+  if ((usbframe & 0xf) == 1) {
+    if (ctx->flushed == 0) {
+      for (int i = 0; i < USBDEV_NUM_ENDPOINTS; i++) {
+        if (ctx->flush[i]) {
+          ctx->flush[i](ctx->ep_ctx[i]);
+        }
+      }
+      ctx->flushed = 1;
+    }
+  } else {
+    ctx->flushed = 0;
+  }
+  // TODO Errors? What Errors?
+}
+
+void usb_testutils_endpoint_setup(
+    usb_testutils_ctx_t *ctx, int ep,
+    usb_testutils_out_transfer_mode_t out_mode, void *ep_ctx,
+    void (*tx_done)(void *),
+    void (*rx)(void *, dif_usbdev_rx_packet_info_t, dif_usbdev_buffer_t),
+    void (*flush)(void *), void (*reset)(void *)) {
+  ctx->ep_ctx[ep] = ep_ctx;
+  ctx->tx_done_callback[ep] = tx_done;
+  ctx->rx_callback[ep] = rx;
+  ctx->flush[ep] = flush;
+  ctx->reset[ep] = reset;
+
+  dif_usbdev_endpoint_id_t endpoint = {
+      .number = ep,
+      .direction = USBDEV_ENDPOINT_DIR_IN,
+  };
+  CHECK_DIF_OK(
+      dif_usbdev_endpoint_enable(ctx->dev, endpoint, kDifToggleEnabled));
+
+  endpoint.direction = USBDEV_ENDPOINT_DIR_OUT;
+  if (out_mode != kUsbdevOutDisabled) {
+    CHECK_DIF_OK(
+        dif_usbdev_endpoint_enable(ctx->dev, endpoint, kDifToggleEnabled));
+    CHECK_DIF_OK(dif_usbdev_endpoint_out_enable(ctx->dev, endpoint.number,
+                                                kDifToggleEnabled));
+  }
+  if (out_mode == kUsbdevOutMessage) {
+    CHECK_DIF_OK(dif_usbdev_endpoint_set_nak_out_enable(
+        ctx->dev, endpoint.number, kDifToggleEnabled));
+  }
+}
+
+void usb_testutils_init(usb_testutils_ctx_t *ctx, bool pinflip,
+                        bool en_diff_rcvr, bool tx_use_d_se0) {
+  CHECK(ctx != NULL);
+  ctx->dev = &usbdev;
+  ctx->buffer_pool = &buffer_pool;
+
+  CHECK_DIF_OK(
+      dif_usbdev_init(mmio_region_from_addr(USBDEV_BASE_ADDR), ctx->dev));
+
+  dif_usbdev_config_t config = {
+      .have_differential_receiver = dif_bool_to_toggle(en_diff_rcvr),
+      .use_tx_d_se0 = dif_bool_to_toggle(tx_use_d_se0),
+      .single_bit_eop = kDifToggleDisabled,
+      .pin_flip = dif_bool_to_toggle(pinflip),
+      .clock_sync_signals = kDifToggleEnabled,
+  };
+  CHECK_DIF_OK(dif_usbdev_configure(ctx->dev, ctx->buffer_pool, config));
+
+  // setup context
+  for (int i = 0; i < USBDEV_NUM_ENDPOINTS; i++) {
+    usb_testutils_endpoint_setup(ctx, i, kUsbdevOutDisabled, NULL, NULL, NULL,
+                                 NULL, NULL);
+  }
+
+  // All about polling...
+  CHECK_DIF_OK(dif_usbdev_irq_disable_all(ctx->dev, NULL));
+
+  // Provide buffers for any reception
+  CHECK_DIF_OK(dif_usbdev_fill_available_fifo(ctx->dev, ctx->buffer_pool));
+
+  dif_usbdev_endpoint_id_t endpoint = {
+      .number = 0,
+      .direction = 1,
+  };
+  CHECK_DIF_OK(
+      dif_usbdev_endpoint_enable(ctx->dev, endpoint, kDifToggleEnabled));
+  CHECK_DIF_OK(
+      dif_usbdev_endpoint_stall_enable(ctx->dev, endpoint, kDifToggleDisabled));
+
+  endpoint.direction = 0;
+  CHECK_DIF_OK(
+      dif_usbdev_endpoint_enable(ctx->dev, endpoint, kDifToggleEnabled));
+  CHECK_DIF_OK(
+      dif_usbdev_endpoint_stall_enable(ctx->dev, endpoint, kDifToggleDisabled));
+  CHECK_DIF_OK(dif_usbdev_endpoint_setup_enable(ctx->dev, endpoint.number,
+                                                kDifToggleEnabled));
+  CHECK_DIF_OK(dif_usbdev_endpoint_out_enable(ctx->dev, endpoint.number,
+                                              kDifToggleEnabled));
+}
+
+// `extern` declarations to give the inline functions in the
+// corresponding header a link location.
+
+extern int usb_testutils_halted(usb_testutils_ctx_t *ctx,
+                                dif_usbdev_endpoint_id_t endpoint);
diff --git a/sw/device/lib/testing/usb_testutils.h b/sw/device/lib/testing/usb_testutils.h
new file mode 100644
index 0000000..1f57059
--- /dev/null
+++ b/sw/device/lib/testing/usb_testutils.h
@@ -0,0 +1,109 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef OPENTITAN_SW_DEVICE_LIB_TESTING_USB_TESTUTILS_H_
+#define OPENTITAN_SW_DEVICE_LIB_TESTING_USB_TESTUTILS_H_
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "sw/device/lib/dif/dif_usbdev.h"
+
+typedef struct usb_testutils_ctx usb_testutils_ctx_t;
+
+struct usb_testutils_ctx {
+  dif_usbdev_t *dev;
+  dif_usbdev_buffer_pool_t *buffer_pool;
+  int flushed;
+  void *ep_ctx[USBDEV_NUM_ENDPOINTS];
+  void (*tx_done_callback[USBDEV_NUM_ENDPOINTS])(void *);
+  void (*rx_callback[USBDEV_NUM_ENDPOINTS])(void *, dif_usbdev_rx_packet_info_t,
+                                            dif_usbdev_buffer_t);
+  void (*flush[USBDEV_NUM_ENDPOINTS])(void *);
+  void (*reset[USBDEV_NUM_ENDPOINTS])(void *);
+};
+
+/**
+ * Call regularly to poll the usbdev interface
+ *
+ * @param ctx usbdev context pointer
+ */
+void usb_testutils_poll(usb_testutils_ctx_t *ctx);
+
+typedef enum usb_testutils_out_transfer_mode {
+  /**
+   * The endpoint does not support OUT transactions.
+   */
+  kUsbdevOutDisabled = 0,
+  /**
+   * Software does NOT need to call usb_testutils_clear_out_nak() after every
+   * received transaction. If software takes no action, usbdev will allow an
+   * endpoint's transactions to proceed as long as a buffer is available.
+   */
+  kUsbdevOutStream = 1,
+  /**
+   * Software must call usb_testutils_clear_out_nak() after every received
+   * transaction to re-enable packet reception. This gives software time to
+   * respond with the appropriate handshake when it's ready.
+   */
+  kUsbdevOutMessage = 2,
+} usb_testutils_out_transfer_mode_t;
+
+/**
+ * Call to set up endpoints.
+ *
+ * Note that this library currently only supports setting up both the IN and OUT
+ * endpoints in the same call, using the same `ep_ctx` for their callbacks.
+ *
+ * @param ctx usbdev context pointer
+ * @param ep endpoint number
+ * @param out_mode the transfer mode for OUT transactions
+ * @param ep_ctx context pointer for callee
+ * @param tx_done(void *ep_ctx) callback once send has been Acked
+ * @param rx(void *ep_ctx, usbbufid_t buf, int size, int setup)
+          called when a packet is received
+ * @param flush(void *ep_ctx) called every 16ms based USB host timebase
+ * @param reset(void *ep_ctx) called when an USB link reset is detected
+ */
+void usb_testutils_endpoint_setup(usb_testutils_ctx_t *ctx, int ep,
+                                  usb_testutils_out_transfer_mode_t out_mode,
+                                  void *ep_ctx, void (*tx_done)(void *),
+                                  void (*rx)(void *,
+                                             dif_usbdev_rx_packet_info_t,
+                                             dif_usbdev_buffer_t),
+                                  void (*flush)(void *), void (*reset)(void *));
+
+/**
+ * Initialize the usbdev interface
+ *
+ * Does not connect the device, since the default endpoint is not yet enabled.
+ * See usb_testutils_connect().
+ *
+ * @param ctx uninitialized usbdev context pointer
+ * @param pinflip boolean to indicate if PHY should be configured for D+/D- flip
+ * @param en_diff_rcvr boolean to indicate if PHY should enable an external
+ *                     differential receiver, activating the single-ended D
+ *                     input
+ * @param tx_use_d_se0 boolean to indicate if PHY uses D/SE0 for TX instead of
+ *                     Dp/Dn
+ */
+void usb_testutils_init(usb_testutils_ctx_t *ctx, bool pinflip,
+                        bool en_diff_rcvr, bool tx_use_d_se0);
+
+// Used for tracing what is going on. This may impact timing which is critical
+// when simulating with the USB DPI module.
+// #define ENABLE_TRC
+#ifdef ENABLE_TRC
+#include "sw/device/lib/runtime/log.h"
+#define TRC_S(s) LOG_INFO("%s", s)
+#define TRC_I(i, b) LOG_INFO("0x%x", i)
+#define TRC_C(c) LOG_INFO("%c", c)
+#else
+#define TRC_S(s)
+#define TRC_I(i, b)
+#define TRC_C(c)
+#endif
+
+#endif  // OPENTITAN_SW_DEVICE_LIB_TESTING_USB_TESTUTILS_H_
diff --git a/sw/device/lib/testing/usb_testutils_controlep.c b/sw/device/lib/testing/usb_testutils_controlep.c
new file mode 100644
index 0000000..698f6d5
--- /dev/null
+++ b/sw/device/lib/testing/usb_testutils_controlep.c
@@ -0,0 +1,340 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include "sw/device/lib/testing/usb_testutils_controlep.h"
+
+#include "sw/device/lib/dif/dif_usbdev.h"
+#include "sw/device/lib/testing/test_framework/check.h"
+#include "sw/device/lib/testing/usb_testutils.h"
+
+// Device descriptor
+static uint8_t dev_dscr[] = {
+    18,    // bLength
+    1,     // bDescriptorType
+    0x00,  // bcdUSB[0]
+    0x02,  // bcdUSB[1]
+    0x00,  // bDeviceClass (defined at interface level)
+    0x00,  // bDeviceSubClass
+    0x00,  // bDeviceProtocol
+    64,    // bMaxPacketSize0
+
+    0xd1,  // idVendor[0] 0x18d1 Google Inc.
+    0x18,  // idVendor[1]
+    0x3a,  // idProduct[0] lowRISC generic FS USB
+    0x50,  // idProduct[1] (allocated by Google)
+
+    0,    // bcdDevice[0]
+    0x1,  // bcdDevice[1]
+    0,    // iManufacturer
+    0,    // iProduct
+    0,    // iSerialNumber
+    1     // bNumConfigurations
+};
+
+// SETUP requests
+typedef enum usb_setup_req {
+  kUsbSetupReqGetStatus = 0,
+  kUsbSetupReqClearFeature = 1,
+  kUsbSetupReqSetFeature = 3,
+  kUsbSetupReqSetAddress = 5,
+  kUsbSetupReqGetDescriptor = 6,
+  kUsbSetupReqSetDescriptor = 7,
+  kUsbSetupReqGetConfiguration = 8,
+  kUsbSetupReqSetConfiguration = 9,
+  kUsbSetupReqGetInterface = 10,
+  kUsbSetupReqSetInterface = 11,
+  kUsbSetupReqSynchFrame = 12
+} usb_setup_req_t;
+
+typedef enum usb_req_type {  // bmRequestType
+  kUsbReqTypeRecipientMask = 0x1f,
+  kUsbReqTypeDevice = 0,
+  kUsbReqTypeInterface = 1,
+  kUsbReqTypeEndpoint = 2,
+  kUsbReqTypeOther = 3,
+  kUsbReqTypeTypeMask = 0x60,
+  KUsbReqTypeStandard = 0,
+  KUsbReqTypeClass = 0x20,
+  KUsbReqTypeVendor = 0x40,
+  KUsbReqTypeReserved = 0x60,
+  kUsbReqTypeDirMask = 0x80,
+  kUsbReqTypeDirH2D = 0x00,
+  kUsbReqTypeDirD2H = 0x80,
+} usb_req_type_t;
+
+typedef enum usb_feature_req {
+  kUsbFeatureEndpointHalt = 0,        // recipient is endpoint
+  kUsbFeatureDeviceRemoteWakeup = 1,  // recipient is device
+  kUsbFeatureTestMode = 2,            // recipient is device
+  kUsbFeatureBHnpEnable = 3,          // recipient is device only if OTG
+  kUsbFeatureAHnpSupport = 4,         // recipient is device only if OTG
+  kUsbFeatureAAltHnpSupport = 5       // recipient is device only if OTG
+} usb_feature_req_t;
+
+typedef enum usb_status {
+  kUsbStatusSelfPowered = 1,  // Device status request
+  kUsbStatusRemWake = 2,      // Device status request
+  kUsbStatusHalted = 1        // Endpoint status request
+} usb_status_t;
+
+static usb_testutils_ctstate_t setup_req(usb_testutils_controlep_ctx_t *ctctx,
+                                         usb_testutils_ctx_t *ctx,
+                                         int bmRequestType, int bRequest,
+                                         int wValue, int wIndex, int wLength) {
+  size_t len;
+  uint32_t stat;
+  int zero, type;
+  size_t bytes_written;
+  dif_usbdev_endpoint_id_t endpoint = {
+      .number = bmRequestType & 0x0f,
+      .direction = bmRequestType & 0x80,
+  };
+  dif_usbdev_buffer_t buffer;
+  CHECK_DIF_OK(dif_usbdev_buffer_request(ctx->dev, ctx->buffer_pool, &buffer));
+  switch (bRequest) {
+    case kUsbSetupReqGetDescriptor:
+      if ((wValue & 0xff00) == 0x100) {
+        // Device descriptor
+        len = sizeof(dev_dscr);
+        if (wLength < len) {
+          len = wLength;
+        }
+        CHECK_DIF_OK(dif_usbdev_buffer_write(ctx->dev, &buffer, dev_dscr, len,
+                                             &bytes_written));
+        CHECK_DIF_OK(dif_usbdev_send(ctx->dev, ctctx->ep, &buffer));
+        return kUsbTestutilsCtWaitIn;
+      } else if ((wValue & 0xff00) == 0x200) {
+        // Configuration descriptor
+        len = ctctx->cfg_dscr_len;
+        if (wLength < len) {
+          len = wLength;
+        }
+        CHECK_DIF_OK(dif_usbdev_buffer_write(ctx->dev, &buffer, ctctx->cfg_dscr,
+                                             len, &bytes_written));
+        CHECK_DIF_OK(dif_usbdev_send(ctx->dev, ctctx->ep, &buffer));
+        return kUsbTestutilsCtWaitIn;
+      }
+      return kUsbTestutilsCtError;  // unknown
+
+    case kUsbSetupReqSetAddress:
+      ctctx->new_dev = wValue & 0x7f;
+      // send zero length packet for status phase
+      CHECK_DIF_OK(dif_usbdev_send(ctx->dev, ctctx->ep, &buffer));
+      return kUsbTestutilsCtAddrStatIn;
+
+    case kUsbSetupReqSetConfiguration:
+      // only ever expect this to be 1 since there is one config descriptor
+      ctctx->usb_config = wValue;
+      // send zero length packet for status phase
+      CHECK_DIF_OK(dif_usbdev_send(ctx->dev, ctctx->ep, &buffer));
+      ctctx->device_state = kUsbTestutilsDeviceConfigured;
+      return kUsbTestutilsCtStatIn;
+
+    case kUsbSetupReqGetConfiguration:
+      len = sizeof(ctctx->usb_config);
+      if (wLength < len) {
+        len = wLength;
+      }
+      // return the value that was set
+      CHECK_DIF_OK(dif_usbdev_buffer_write(
+          ctx->dev, &buffer, &ctctx->usb_config, len, &bytes_written));
+      CHECK_DIF_OK(dif_usbdev_send(ctx->dev, ctctx->ep, &buffer));
+      return kUsbTestutilsCtWaitIn;
+
+    case kUsbSetupReqSetFeature:
+      if (wValue == kUsbFeatureEndpointHalt) {
+        CHECK_DIF_OK(dif_usbdev_endpoint_stall_enable(ctx->dev, endpoint,
+                                                      kDifToggleEnabled));
+        // send zero length packet for status phase
+        CHECK_DIF_OK(dif_usbdev_send(ctx->dev, ctctx->ep, &buffer));
+        return kUsbTestutilsCtStatIn;
+      }
+      return kUsbTestutilsCtError;  // unknown
+
+    case kUsbSetupReqClearFeature:
+      if (wValue == kUsbFeatureEndpointHalt) {
+        CHECK_DIF_OK(dif_usbdev_endpoint_stall_enable(ctx->dev, endpoint,
+                                                      kDifToggleDisabled));
+        // send zero length packet for status phase
+        CHECK_DIF_OK(dif_usbdev_send(ctx->dev, ctctx->ep, &buffer));
+      }
+      return kUsbTestutilsCtStatIn;
+
+    case kUsbSetupReqGetStatus:
+      len = 2;
+      type = bmRequestType & kUsbReqTypeRecipientMask;
+      if (type == kUsbReqTypeDevice) {
+        stat = kUsbStatusSelfPowered;
+      } else if (type == kUsbReqTypeEndpoint) {
+        bool halted;
+        CHECK_DIF_OK(
+            dif_usbdev_endpoint_stall_get(ctx->dev, endpoint, &halted));
+        stat = halted ? kUsbStatusHalted : 0;
+      } else {
+        stat = 0;
+      }
+      if (wLength < len) {
+        len = wLength;
+      }
+      // return the value that was set
+      CHECK_DIF_OK(dif_usbdev_buffer_write(ctx->dev, &buffer, (uint8_t *)&stat,
+                                           len, &bytes_written));
+      CHECK_DIF_OK(dif_usbdev_send(ctx->dev, ctctx->ep, &buffer));
+      return kUsbTestutilsCtWaitIn;
+
+    case kUsbSetupReqSetInterface:
+      // Don't support alternate interfaces, so just ignore
+      // send zero length packet for status phase
+      CHECK_DIF_OK(dif_usbdev_send(ctx->dev, ctctx->ep, &buffer));
+      return kUsbTestutilsCtStatIn;
+
+    case kUsbSetupReqGetInterface:
+      zero = 0;
+      len = 1;
+      if (wLength < len) {
+        len = wLength;
+      }
+      // Don't support interface, so return zero
+      CHECK_DIF_OK(dif_usbdev_buffer_write(ctx->dev, &buffer, (uint8_t *)&zero,
+                                           len, &bytes_written));
+      CHECK_DIF_OK(dif_usbdev_send(ctx->dev, ctctx->ep, &buffer));
+      return kUsbTestutilsCtWaitIn;
+
+    case kUsbSetupReqSynchFrame:
+      zero = 0;
+      len = 2;
+      if (wLength < len) {
+        len = wLength;
+      }
+      // Don't support synch_frame so return zero
+      CHECK_DIF_OK(dif_usbdev_buffer_write(ctx->dev, &buffer, (uint8_t *)&zero,
+                                           len, &bytes_written));
+      CHECK_DIF_OK(dif_usbdev_send(ctx->dev, ctctx->ep, &buffer));
+      return kUsbTestutilsCtWaitIn;
+
+    default:
+      return kUsbTestutilsCtError;
+  }
+  return kUsbTestutilsCtError;
+}
+
+static void ctrl_tx_done(void *ctctx_v) {
+  usb_testutils_controlep_ctx_t *ctctx =
+      (usb_testutils_controlep_ctx_t *)ctctx_v;
+  usb_testutils_ctx_t *ctx = ctctx->ctx;
+  TRC_C('A' + ctctx->ctrlstate);
+  switch (ctctx->ctrlstate) {
+    case kUsbTestutilsCtAddrStatIn:
+      // Now the status was sent on device 0 can switch to new device ID
+      CHECK_DIF_OK(dif_usbdev_address_set(ctx->dev, ctctx->new_dev));
+      TRC_I(ctctx->new_dev, 8);
+      ctctx->ctrlstate = kUsbTestutilsCtIdle;
+      // Should be kUsbTestutilsDeviceAddressed only, but test controller is
+      // borked ctctx->device_state = kUsbTestutilsDeviceAddressed;
+      ctctx->device_state = kUsbTestutilsDeviceConfigured;
+      return;
+    case kUsbTestutilsCtStatIn:
+      ctctx->ctrlstate = kUsbTestutilsCtIdle;
+      return;
+    case kUsbTestutilsCtWaitIn:
+      ctctx->ctrlstate = kUsbTestutilsCtStatOut;
+      return;
+    default:
+      break;
+  }
+  TRC_S("USB: unexpected IN ");
+  TRC_I((ctctx->ctrlstate << 24), 32);
+}
+
+static void ctrl_rx(void *ctctx_v, dif_usbdev_rx_packet_info_t packet_info,
+                    dif_usbdev_buffer_t buffer) {
+  usb_testutils_controlep_ctx_t *ctctx =
+      (usb_testutils_controlep_ctx_t *)ctctx_v;
+  usb_testutils_ctx_t *ctx = ctctx->ctx;
+  CHECK_DIF_OK(dif_usbdev_endpoint_out_enable(ctx->dev, /*endpoint=*/0,
+                                              kDifToggleEnabled));
+
+  TRC_C('0' + ctctx->ctrlstate);
+  uint32_t bytes_written;
+  // TODO: Should check for canceled IN transactions due to receiving a SETUP
+  // packet.
+  switch (ctctx->ctrlstate) {
+    case kUsbTestutilsCtIdle:
+      // Waiting to be set up
+      if (packet_info.is_setup && (packet_info.length == 8)) {
+        alignas(uint32_t) uint8_t bp[8];
+        CHECK_DIF_OK(dif_usbdev_buffer_read(ctx->dev, ctx->buffer_pool, &buffer,
+                                            bp, sizeof(bp), &bytes_written));
+        int bmRequestType = bp[0];
+        int bRequest = bp[1];
+        int wValue = (bp[3] << 8) | bp[2];
+        int wIndex = (bp[5] << 8) | bp[4];
+        int wLength = (bp[7] << 8) | bp[6];
+        TRC_C('0' + bRequest);
+
+        ctctx->ctrlstate = setup_req(ctctx, ctx, bmRequestType, bRequest,
+                                     wValue, wIndex, wLength);
+        if (ctctx->ctrlstate != kUsbTestutilsCtError) {
+          return;
+        }
+      }
+      break;
+
+    case kUsbTestutilsCtStatOut:
+      // Have sent some data, waiting STATUS stage
+      if (!packet_info.is_setup && (packet_info.length == 0)) {
+        CHECK_DIF_OK(
+            dif_usbdev_buffer_return(ctx->dev, ctx->buffer_pool, &buffer));
+        ctctx->ctrlstate = kUsbTestutilsCtIdle;
+        return;
+      }
+      // anything else is unexpected
+      break;
+
+    default:
+      // Error
+      break;
+  }
+  dif_usbdev_endpoint_id_t endpoint = {
+      .number = 0,
+      .direction = USBDEV_ENDPOINT_DIR_IN,
+  };
+  // Enable responding with STALL. Will be cleared by the HW.
+  CHECK_DIF_OK(
+      dif_usbdev_endpoint_stall_enable(ctx->dev, endpoint, kDifToggleEnabled));
+  endpoint.direction = USBDEV_ENDPOINT_DIR_OUT;
+  CHECK_DIF_OK(
+      dif_usbdev_endpoint_stall_enable(ctx->dev, endpoint, kDifToggleEnabled));
+  TRC_S("USB: unCT ");
+  TRC_I((ctctx->ctrlstate << 24) | setup << 16 | size, 32);
+  TRC_C(':');
+  for (int i = 0; i < packet_info.length; i++) {
+    TRC_I(bp[i], 8);
+    TRC_C(' ');
+  }
+  CHECK_DIF_OK(dif_usbdev_buffer_return(ctx->dev, ctx->buffer_pool, &buffer));
+  ctctx->ctrlstate = kUsbTestutilsCtIdle;
+}
+
+// Callback for the USB link reset
+static void ctrl_reset(void *ctctx_v) {
+  usb_testutils_controlep_ctx_t *ctctx =
+      (usb_testutils_controlep_ctx_t *)ctctx_v;
+  ctctx->ctrlstate = kUsbTestutilsCtIdle;
+}
+
+void usb_testutils_controlep_init(usb_testutils_controlep_ctx_t *ctctx,
+                                  usb_testutils_ctx_t *ctx, int ep,
+                                  const uint8_t *cfg_dscr,
+                                  size_t cfg_dscr_len) {
+  ctctx->ctx = ctx;
+  usb_testutils_endpoint_setup(ctx, ep, kUsbdevOutMessage, ctctx, ctrl_tx_done,
+                               ctrl_rx, NULL, ctrl_reset);
+  ctctx->ep = ep;
+  ctctx->ctrlstate = kUsbTestutilsCtIdle;
+  ctctx->cfg_dscr = cfg_dscr;
+  ctctx->cfg_dscr_len = cfg_dscr_len;
+  CHECK_DIF_OK(dif_usbdev_interface_enable(ctx->dev, kDifToggleEnabled));
+  ctctx->device_state = kUsbTestutilsDeviceDefault;
+}
diff --git a/sw/device/lib/usb_controlep.h b/sw/device/lib/testing/usb_testutils_controlep.h
similarity index 73%
rename from sw/device/lib/usb_controlep.h
rename to sw/device/lib/testing/usb_testutils_controlep.h
index 9333af1..eeacbd4 100644
--- a/sw/device/lib/usb_controlep.h
+++ b/sw/device/lib/testing/usb_testutils_controlep.h
@@ -2,42 +2,43 @@
 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
 // SPDX-License-Identifier: Apache-2.0
 
-#ifndef OPENTITAN_SW_DEVICE_LIB_USB_CONTROLEP_H_
-#define OPENTITAN_SW_DEVICE_LIB_USB_CONTROLEP_H_
+#ifndef OPENTITAN_SW_DEVICE_LIB_TESTING_USB_TESTUTILS_CONTROLEP_H_
+#define OPENTITAN_SW_DEVICE_LIB_TESTING_USB_TESTUTILS_CONTROLEP_H_
 
 #include <stddef.h>
 #include <stdint.h>
 
-#include "sw/device/lib/usbdev.h"
+#include "sw/device/lib/testing/usb_testutils.h"
 
-typedef enum ctstate {
-  kCtIdle,
-  kCtWaitIn,      // Queued IN data stage, waiting ack
-  kCtStatOut,     // Waiting for OUT status stage
-  kCtAddrStatIn,  // Queued status stage, waiting ack afterwhich set dev_addr
-  kCtStatIn,      // Queued status stage, waiting ack
-  kCtError        // Something bad
-} ctstate_t;
+typedef enum usb_testutils_ctstate {
+  kUsbTestutilsCtIdle,
+  kUsbTestutilsCtWaitIn,      // Queued IN data stage, waiting ack
+  kUsbTestutilsCtStatOut,     // Waiting for OUT status stage
+  kUsbTestutilsCtAddrStatIn,  // Queued status stage, waiting ack afterwhich set
+                              // dev_addr
+  kUsbTestutilsCtStatIn,      // Queued status stage, waiting ack
+  kUsbTestutilsCtError        // Something bad
+} usb_testutils_ctstate_t;
 
-typedef enum usbdevice_state {
-  kUsbDeviceAttached,
-  kUsbDevicePowered,
-  kUsbDeviceDefault,
-  kUsbDeviceAddressed,
-  kUsbDeviceConfigured,
-  kUsbDeviceSuspended,
-} usb_device_state_t;
+typedef enum usb_testutils_device_state {
+  kUsbTestutilsDeviceAttached,
+  kUsbTestutilsDevicePowered,
+  kUsbTestutilsDeviceDefault,
+  kUsbTestutilsDeviceAddressed,
+  kUsbTestutilsDeviceConfigured,
+  kUsbTestutilsDeviceSuspended,
+} usb_testutils_device_state_t;
 
-typedef struct usb_controlep_ctx {
-  usbdev_ctx_t *ctx;
+typedef struct usb_testutils_controlep_ctx {
+  usb_testutils_ctx_t *ctx;
   int ep;
-  ctstate_t ctrlstate;
-  usb_device_state_t device_state;
+  usb_testutils_ctstate_t ctrlstate;
+  usb_testutils_device_state_t device_state;
   uint32_t new_dev;
   uint8_t usb_config;
   const uint8_t *cfg_dscr;
   size_t cfg_dscr_len;
-} usb_controlep_ctx_t;
+} usb_testutils_controlep_ctx_t;
 
 /**
  * Initialize control endpoint
@@ -48,8 +49,9 @@
  * @param cfg_dscr configuration descriptor for the device
  * @param cfg_dscr_len length of cfg_dscr
  */
-void usb_controlep_init(usb_controlep_ctx_t *ctctx, usbdev_ctx_t *ctx, int ep,
-                        const uint8_t *cfg_dscr, size_t cfg_dscr_len);
+void usb_testutils_controlep_init(usb_testutils_controlep_ctx_t *ctctx,
+                                  usb_testutils_ctx_t *ctx, int ep,
+                                  const uint8_t *cfg_dscr, size_t cfg_dscr_len);
 
 /********************************************************************/
 /* Below this point are macros used to construct the USB descriptor */
@@ -104,4 +106,4 @@
 
 // KEEP BLANK LINE ABOVE, it is in the macro!
 
-#endif  // OPENTITAN_SW_DEVICE_LIB_USB_CONTROLEP_H_
+#endif  // OPENTITAN_SW_DEVICE_LIB_TESTING_USB_TESTUTILS_CONTROLEP_H_
diff --git a/sw/device/lib/testing/usb_testutils_simpleserial.c b/sw/device/lib/testing/usb_testutils_simpleserial.c
new file mode 100644
index 0000000..05a799d
--- /dev/null
+++ b/sw/device/lib/testing/usb_testutils_simpleserial.c
@@ -0,0 +1,76 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include "sw/device/lib/testing/usb_testutils_simpleserial.h"
+
+#include "sw/device/lib/dif/dif_usbdev.h"
+#include "sw/device/lib/testing/test_framework/check.h"
+#include "sw/device/lib/testing/usb_testutils.h"
+
+#define MAX_GATHER 16
+
+static void ss_rx(void *ssctx_v, dif_usbdev_rx_packet_info_t packet_info,
+                  dif_usbdev_buffer_t buffer) {
+  usb_testutils_ss_ctx_t *ssctx = (usb_testutils_ss_ctx_t *)ssctx_v;
+  usb_testutils_ctx_t *ctx = ssctx->ctx;
+
+  while (packet_info.length--) {
+    uint8_t data;
+    size_t bytes_written;
+    CHECK_DIF_OK(dif_usbdev_buffer_read(ctx->dev, ctx->buffer_pool, &buffer,
+                                        &data, sizeof(data), &bytes_written));
+    ssctx->got_byte(data);
+  }
+}
+
+// Called periodically by the main loop to ensure characters don't
+// stick around too long
+static void ss_flush(void *ssctx_v) {
+  usb_testutils_ss_ctx_t *ssctx = (usb_testutils_ss_ctx_t *)ssctx_v;
+  usb_testutils_ctx_t *ctx = ssctx->ctx;
+  if (ssctx->cur_cpos <= 0) {
+    return;
+  }
+  if ((ssctx->cur_cpos & 0x3) != 0) {
+    size_t bytes_written;
+    CHECK_DIF_OK(dif_usbdev_buffer_write(ctx->dev, &ssctx->cur_buf,
+                                         ssctx->chold.data_b, /*src_len=*/4,
+                                         &bytes_written));
+  }
+  CHECK_DIF_OK(dif_usbdev_send(ctx->dev, ssctx->ep, &ssctx->cur_buf));
+  ssctx->cur_cpos = -1;  // given it to the hardware
+}
+
+// Simple send byte will gather data for a while and send
+void usb_testutils_simpleserial_send_byte(usb_testutils_ss_ctx_t *ssctx,
+                                          uint8_t c) {
+  usb_testutils_ctx_t *ctx = ssctx->ctx;
+  if (ssctx->cur_cpos == -1) {
+    CHECK_DIF_OK(
+        dif_usbdev_buffer_request(ctx->dev, ctx->buffer_pool, &ssctx->cur_buf));
+    ssctx->cur_cpos = 0;
+  }
+  ssctx->chold.data_b[ssctx->cur_cpos++ & 0x3] = c;
+  if ((ssctx->cur_cpos & 0x3) == 0) {
+    size_t bytes_written;
+    CHECK_DIF_OK(dif_usbdev_buffer_write(ctx->dev, &ssctx->cur_buf,
+                                         ssctx->chold.data_b, /*src_len=*/4,
+                                         &bytes_written));
+    if (ssctx->cur_cpos >= MAX_GATHER) {
+      CHECK_DIF_OK(dif_usbdev_send(ctx->dev, ssctx->ep, &ssctx->cur_buf));
+      ssctx->cur_cpos = -1;  // given it to the hardware
+    }
+  }
+}
+
+void usb_testutils_simpleserial_init(usb_testutils_ss_ctx_t *ssctx,
+                                     usb_testutils_ctx_t *ctx, int ep,
+                                     void (*got_byte)(uint8_t)) {
+  usb_testutils_endpoint_setup(ctx, ep, kUsbdevOutStream, ssctx, NULL, ss_rx,
+                               ss_flush, NULL);
+  ssctx->ctx = ctx;
+  ssctx->ep = ep;
+  ssctx->got_byte = got_byte;
+  ssctx->cur_cpos = -1;
+}
diff --git a/sw/device/lib/testing/usb_testutils_simpleserial.h b/sw/device/lib/testing/usb_testutils_simpleserial.h
new file mode 100644
index 0000000..3172f87
--- /dev/null
+++ b/sw/device/lib/testing/usb_testutils_simpleserial.h
@@ -0,0 +1,48 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef OPENTITAN_SW_DEVICE_LIB_TESTING_USB_TESTUTILS_SIMPLESERIAL_H_
+#define OPENTITAN_SW_DEVICE_LIB_TESTING_USB_TESTUTILS_SIMPLESERIAL_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "sw/device/lib/dif/dif_usbdev.h"
+#include "sw/device/lib/testing/usb_testutils.h"
+
+// This is only here because caller of _init needs it
+typedef struct usb_testutils_ss_ctx {
+  usb_testutils_ctx_t *ctx;
+  int ep;
+  dif_usbdev_buffer_t cur_buf;
+  int cur_cpos;
+  union usb_ss_b2w {
+    uint32_t data_w;
+    uint8_t data_b[4];
+  } chold;
+  void (*got_byte)(uint8_t);
+} usb_testutils_ss_ctx_t;
+
+/**
+ * Send a byte on a simpleserial endpoint
+ *
+ * @param ssctx instance context
+ * @param c byte to send
+ */
+void usb_testutils_simpleserial_send_byte(usb_testutils_ss_ctx_t *ssctx,
+                                          uint8_t c);
+
+/**
+ * Initialize a simpleserial endpoint
+ *
+ * @param ssctx unintialized simpleserial instance context
+ * @param ctx initialized usbdev context
+ * @param ep endpoint number for this instance
+ * @param got_byte callback function for when a byte is received
+ */
+void usb_testutils_simpleserial_init(usb_testutils_ss_ctx_t *ssctx,
+                                     usb_testutils_ctx_t *ctx, int ep,
+                                     void (*got_byte)(uint8_t));
+
+#endif  // OPENTITAN_SW_DEVICE_LIB_TESTING_USB_TESTUTILS_SIMPLESERIAL_H_
diff --git a/sw/device/lib/usb_consts.h b/sw/device/lib/usb_consts.h
deleted file mode 100644
index 460393f..0000000
--- a/sw/device/lib/usb_consts.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-
-#ifndef OPENTITAN_SW_DEVICE_LIB_USB_CONSTS_H_
-#define OPENTITAN_SW_DEVICE_LIB_USB_CONSTS_H_
-
-// SETUP requests
-typedef enum usb_setup_req {
-  kUsbSetupReqGetStatus = 0,
-  kUsbSetupReqClearFeature = 1,
-  kUsbSetupReqSetFeature = 3,
-  kUsbSetupReqSetAddress = 5,
-  kUsbSetupReqGetDescriptor = 6,
-  kUsbSetupReqSetDescriptor = 7,
-  kUsbSetupReqGetConfiguration = 8,
-  kUsbSetupReqSetConfiguration = 9,
-  kUsbSetupReqGetInterface = 10,
-  kUsbSetupReqSetInterface = 11,
-  kUsbSetupReqSynchFrame = 12
-} usb_setup_req_t;
-
-typedef enum usb_req_type {  // bmRequestType
-  kUsbReqTypeRecipientMask = 0x1f,
-  kUsbReqTypeDevice = 0,
-  kUsbReqTypeInterface = 1,
-  kUsbReqTypeEndpoint = 2,
-  kUsbReqTypeOther = 3,
-  kUsbReqTypeTypeMask = 0x60,
-  KUsbReqTypeStandard = 0,
-  KUsbReqTypeClass = 0x20,
-  KUsbReqTypeVendor = 0x40,
-  KUsbReqTypeReserved = 0x60,
-  kUsbReqTypeDirMask = 0x80,
-  kUsbReqTypeDirH2D = 0x00,
-  kUsbReqTypeDirD2H = 0x80,
-} usb_req_type_t;
-
-typedef enum usb_feature_req {
-  kUsbFeatureEndpointHalt = 0,        // recipient is endpoint
-  kUsbFeatureDeviceRemoteWakeup = 1,  // recipient is device
-  kUsbFeatureTestMode = 2,            // recipient is device
-  kUsbFeatureBHnpEnable = 3,          // recipient is device only if OTG
-  kUsbFeatureAHnpSupport = 4,         // recipient is device only if OTG
-  kUsbFeatureAAltHnpSupport = 5       // recipient is device only if OTG
-} usb_feature_req_t;
-
-typedef enum usb_status {
-  kUsbStatusSelfPowered = 1,  // Device status request
-  kUsbStatusRemWake = 2,      // Device status request
-  kUsbStatusHalted = 1        // Endpoint status request
-} usb_status_t;
-
-#endif  // OPENTITAN_SW_DEVICE_LIB_USB_CONSTS_H_
diff --git a/sw/device/lib/usb_controlep.c b/sw/device/lib/usb_controlep.c
deleted file mode 100644
index 466a6bd..0000000
--- a/sw/device/lib/usb_controlep.c
+++ /dev/null
@@ -1,257 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-
-#include "sw/device/lib/usb_controlep.h"
-
-#include "sw/device/lib/usb_consts.h"
-#include "sw/device/lib/usbdev.h"
-
-// Device descriptor
-static uint8_t dev_dscr[] = {
-    18,    // bLength
-    1,     // bDescriptorType
-    0x00,  // bcdUSB[0]
-    0x02,  // bcdUSB[1]
-    0x00,  // bDeviceClass (defined at interface level)
-    0x00,  // bDeviceSubClass
-    0x00,  // bDeviceProtocol
-    64,    // bMaxPacketSize0
-
-    0xd1,  // idVendor[0] 0x18d1 Google Inc.
-    0x18,  // idVendor[1]
-    0x3a,  // idProduct[0] lowRISC generic FS USB
-    0x50,  // idProduct[1] (allocated by Google)
-
-    0,    // bcdDevice[0]
-    0x1,  // bcdDevice[1]
-    0,    // iManufacturer
-    0,    // iProduct
-    0,    // iSerialNumber
-    1     // bNumConfigurations
-};
-
-static ctstate_t setup_req(usb_controlep_ctx_t *ctctx, void *ctx,
-                           usbbufid_t buf, int bmRequestType, int bRequest,
-                           int wValue, int wIndex, int wLength) {
-  size_t len;
-  uint32_t stat;
-  int zero, type;
-  switch (bRequest) {
-    case kUsbSetupReqGetDescriptor:
-      if ((wValue & 0xff00) == 0x100) {
-        // Device descriptor
-        len = sizeof(dev_dscr);
-        if (wLength < len) {
-          len = wLength;
-        }
-        usbdev_buf_copyto_byid(ctx, buf, dev_dscr, len);
-        usbdev_sendbuf_byid(ctx, buf, len, ctctx->ep);
-        return kCtWaitIn;
-      } else if ((wValue & 0xff00) == 0x200) {
-        // Configuration descriptor
-        len = ctctx->cfg_dscr_len;
-        if (wLength < len) {
-          len = wLength;
-        }
-        usbdev_buf_copyto_byid(ctx, buf, ctctx->cfg_dscr, len);
-        usbdev_sendbuf_byid(ctx, buf, len, ctctx->ep);
-        return kCtWaitIn;
-      }
-      return kCtError;  // unknown
-
-    case kUsbSetupReqSetAddress:
-      ctctx->new_dev = wValue & 0x7f;
-      // send zero length packet for status phase
-      usbdev_sendbuf_byid(ctx, buf, 0, ctctx->ep);
-      return kCtAddrStatIn;
-
-    case kUsbSetupReqSetConfiguration:
-      // only ever expect this to be 1 since there is one config descriptor
-      ctctx->usb_config = wValue;
-      // send zero length packet for status phase
-      usbdev_sendbuf_byid(ctx, buf, 0, ctctx->ep);
-      ctctx->device_state = kUsbDeviceConfigured;
-      return kCtStatIn;
-
-    case kUsbSetupReqGetConfiguration:
-      len = sizeof(ctctx->usb_config);
-      if (wLength < len) {
-        len = wLength;
-      }
-      // return the value that was set
-      usbdev_buf_copyto_byid(ctx, buf, &ctctx->usb_config, len);
-      usbdev_sendbuf_byid(ctx, buf, len, ctctx->ep);
-      return kCtWaitIn;
-
-    case kUsbSetupReqSetFeature:
-      if (wValue == kUsbFeatureEndpointHalt) {
-        usbdev_halt(ctx, wIndex, 1);
-      } else if (wValue == kUsbFeatureDeviceRemoteWakeup) {
-        usbdev_rem_wake_en(ctx, 1);
-      }
-      // send zero length packet for status phase
-      usbdev_sendbuf_byid(ctx, buf, 0, ctctx->ep);
-      return kCtStatIn;
-
-    case kUsbSetupReqClearFeature:
-      if (wValue == kUsbFeatureEndpointHalt) {
-        usbdev_halt(ctx, wIndex, 0);
-      } else if (wValue == kUsbFeatureDeviceRemoteWakeup) {
-        usbdev_rem_wake_en(ctx, 0);
-      }
-      // send zero length packet for status phase
-      usbdev_sendbuf_byid(ctx, buf, 0, ctctx->ep);
-      return kCtStatIn;
-
-    case kUsbSetupReqGetStatus:
-      len = 2;
-      type = bmRequestType & kUsbReqTypeRecipientMask;
-      if (type == kUsbReqTypeDevice) {
-        stat = (usbdev_can_rem_wake(ctx) ? kUsbStatusRemWake : 0) |
-               kUsbStatusSelfPowered;
-      } else if (type == kUsbReqTypeEndpoint) {
-        stat = usbdev_halted(ctx, wIndex) ? kUsbStatusHalted : 0;
-      } else {
-        stat = 0;
-      }
-      if (wLength < len) {
-        len = wLength;
-      }
-      // return the value that was set
-      usbdev_buf_copyto_byid(ctx, buf, &stat, len);
-      usbdev_sendbuf_byid(ctx, buf, len, ctctx->ep);
-      return kCtWaitIn;
-
-    case kUsbSetupReqSetInterface:
-      // Don't support alternate interfaces, so just ignore
-      // send zero length packet for status phase
-      usbdev_sendbuf_byid(ctx, buf, 0, ctctx->ep);
-      return kCtStatIn;
-
-    case kUsbSetupReqGetInterface:
-      zero = 0;
-      len = 1;
-      if (wLength < len) {
-        len = wLength;
-      }
-      // Don't support interface, so return zero
-      usbdev_buf_copyto_byid(ctx, buf, &zero, len);
-      usbdev_sendbuf_byid(ctx, buf, len, ctctx->ep);
-      return kCtWaitIn;
-
-    case kUsbSetupReqSynchFrame:
-      zero = 0;
-      len = 2;
-      if (wLength < len) {
-        len = wLength;
-      }
-      // Don't support synch_frame so return zero
-      usbdev_buf_copyto_byid(ctx, buf, &zero, len);
-      usbdev_sendbuf_byid(ctx, buf, len, ctctx->ep);
-      return kCtWaitIn;
-
-    default:
-      return kCtError;
-  }
-  return kCtError;
-}
-
-static void ctrl_tx_done(void *ctctx_v) {
-  usb_controlep_ctx_t *ctctx = (usb_controlep_ctx_t *)ctctx_v;
-  void *ctx = ctctx->ctx;
-  TRC_C('A' + ctctx->ctrlstate);
-  switch (ctctx->ctrlstate) {
-    case kCtAddrStatIn:
-      // Now the status was sent on device 0 can switch to new device ID
-      usbdev_set_deviceid(ctx, ctctx->new_dev);
-      TRC_I(ctctx->new_dev, 8);
-      ctctx->ctrlstate = kCtIdle;
-      // Should be kUsbDeviceAddressed only, but test controller is borked
-      // ctctx->device_state = kUsbDeviceAddressed;
-      ctctx->device_state = kUsbDeviceConfigured;
-      return;
-    case kCtStatIn:
-      ctctx->ctrlstate = kCtIdle;
-      return;
-    case kCtWaitIn:
-      ctctx->ctrlstate = kCtStatOut;
-      return;
-    default:
-      break;
-  }
-  TRC_S("USB: unexpected IN ");
-  TRC_I((ctctx->ctrlstate << 24), 32);
-}
-
-static void ctrl_rx(void *ctctx_v, usbbufid_t buf, int size, int setup) {
-  usb_controlep_ctx_t *ctctx = (usb_controlep_ctx_t *)ctctx_v;
-  void *ctx = ctctx->ctx;
-  usbdev_clear_out_nak(ctx, 0);
-  volatile uint8_t *bp = (volatile uint8_t *)usbdev_buf_idtoaddr(ctx, buf);
-  if (size > BUF_LENGTH) {
-    size = BUF_LENGTH;
-  }
-
-  TRC_C('0' + ctctx->ctrlstate);
-  switch (ctctx->ctrlstate) {
-    case kCtIdle:
-      // Waiting to be set up
-      if (setup && (size == 8)) {
-        int bmRequestType = bp[0];
-        int bRequest = bp[1];
-        int wValue = (bp[3] << 8) | bp[2];
-        int wIndex = (bp[5] << 8) | bp[4];
-        int wLength = (bp[7] << 8) | bp[6];
-        TRC_C('0' + bRequest);
-
-        ctctx->ctrlstate = setup_req(ctctx, ctx, buf, bmRequestType, bRequest,
-                                     wValue, wIndex, wLength);
-        if (ctctx->ctrlstate != kCtError) {
-          return;
-        }
-      }
-      break;
-
-    case kCtStatOut:
-      // Have sent some data, waiting STATUS stage
-      if (!setup && (size == 0)) {
-        ctctx->ctrlstate = kCtIdle;
-        return;
-      }
-      // anything else is unexpected
-      break;
-
-    default:
-      // Error
-      break;
-  }
-  usbdev_set_ep0_stall(ctx, 1);  // send a STALL, will be cleared by the HW
-  TRC_S("USB: unCT ");
-  TRC_I((ctctx->ctrlstate << 24) | setup << 16 | size, 32);
-  TRC_C(':');
-  for (int i = 0; i < size; i++) {
-    TRC_I(bp[i], 8);
-    TRC_C(' ');
-  }
-  usbdev_buf_free_byid(ctx, buf);
-  ctctx->ctrlstate = kCtIdle;
-}
-
-// Callback for the USB link reset
-void ctrl_reset(void *ctctx_v) {
-  usb_controlep_ctx_t *ctctx = (usb_controlep_ctx_t *)ctctx_v;
-  ctctx->ctrlstate = kCtIdle;
-}
-
-void usb_controlep_init(usb_controlep_ctx_t *ctctx, usbdev_ctx_t *ctx, int ep,
-                        const uint8_t *cfg_dscr, size_t cfg_dscr_len) {
-  ctctx->ctx = ctx;
-  usbdev_endpoint_setup(ctx, ep, kUsbdevOutMessage, ctctx, ctrl_tx_done,
-                        ctrl_rx, NULL, ctrl_reset);
-  ctctx->ctrlstate = kCtIdle;
-  ctctx->cfg_dscr = cfg_dscr;
-  ctctx->cfg_dscr_len = cfg_dscr_len;
-  usbdev_connect(ctx);
-  ctctx->device_state = kUsbDeviceDefault;
-}
diff --git a/sw/device/lib/usb_simpleserial.c b/sw/device/lib/usb_simpleserial.c
deleted file mode 100644
index 03ae9a2..0000000
--- a/sw/device/lib/usb_simpleserial.c
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-
-#include "sw/device/lib/usb_simpleserial.h"
-
-#include "sw/device/lib/usbdev.h"
-
-#define MAX_GATHER 16
-
-static void ss_rx(void *ssctx_v, usbbufid_t buf, int size, int setup) {
-  usb_ss_ctx_t *ssctx = (usb_ss_ctx_t *)ssctx_v;
-  void *ctx = ssctx->ctx;
-  volatile uint8_t *bp = (volatile uint8_t *)usbdev_buf_idtoaddr(ctx, buf);
-
-  if (size > BUF_LENGTH) {
-    size = BUF_LENGTH;
-  }
-
-  while (size--) {
-    ssctx->got_byte(*bp++);
-  }
-}
-
-// Called periodically by the main loop to ensure characters don't
-// stick around too long
-static void ss_flush(void *ssctx_v) {
-  usb_ss_ctx_t *ssctx = (usb_ss_ctx_t *)ssctx_v;
-  void *ctx = ssctx->ctx;
-  volatile uint32_t *bp_w;
-  if ((ssctx->cur_buf == -1) || (ssctx->cur_cpos <= 0)) {
-    return;
-  }
-  if ((ssctx->cur_cpos & 0x3) != 0) {
-    // unwritten data to copy over
-    bp_w = usbdev_buf_idtoaddr(ctx, ssctx->cur_buf);
-    // no -1 here because cpos is in the word we are writing
-    bp_w[(ssctx->cur_cpos / 4)] = ssctx->chold.data_w;
-  }
-  usbdev_sendbuf_byid(ctx, ssctx->cur_buf, ssctx->cur_cpos, ssctx->ep);
-  ssctx->cur_buf = -1;  // given it to the hardware
-}
-
-// Simple send byte will gather data for a while and send
-void usb_simpleserial_send_byte(usb_ss_ctx_t *ssctx, uint8_t c) {
-  volatile uint32_t *bp_w;
-  if (ssctx->cur_buf == -1) {
-    ssctx->cur_buf = usbdev_buf_allocate_byid(ssctx->ctx);
-    ssctx->cur_cpos = 0;
-  }
-  // Abort if completely out of buffers and allocation returned -1
-  if (ssctx->cur_buf < 0) {
-    return;
-  }
-  ssctx->chold.data_b[ssctx->cur_cpos++ & 0x3] = c;
-  if ((ssctx->cur_cpos & 0x3) == 0) {
-    // just wrote last byte in word
-    bp_w = usbdev_buf_idtoaddr(ssctx->ctx, ssctx->cur_buf);
-    // -1 here because cpos already incremented to next word
-    bp_w[(ssctx->cur_cpos / 4) - 1] = ssctx->chold.data_w;
-    if (ssctx->cur_cpos >= MAX_GATHER) {
-      usbdev_sendbuf_byid(ssctx->ctx, ssctx->cur_buf, ssctx->cur_cpos,
-                          ssctx->ep);
-      ssctx->cur_buf = -1;  // given it to the hardware
-    }
-  }
-}
-
-void usb_simpleserial_init(usb_ss_ctx_t *ssctx, usbdev_ctx_t *ctx, int ep,
-                           void (*got_byte)(uint8_t)) {
-  usbdev_endpoint_setup(ctx, ep, kUsbdevOutStream, ssctx, NULL, ss_rx, ss_flush,
-                        NULL);
-  ssctx->ctx = ctx;
-  ssctx->ep = ep;
-  ssctx->got_byte = got_byte;
-  ssctx->cur_buf = -1;
-}
diff --git a/sw/device/lib/usb_simpleserial.h b/sw/device/lib/usb_simpleserial.h
deleted file mode 100644
index 8a81875..0000000
--- a/sw/device/lib/usb_simpleserial.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-
-#ifndef OPENTITAN_SW_DEVICE_LIB_USB_SIMPLESERIAL_H_
-#define OPENTITAN_SW_DEVICE_LIB_USB_SIMPLESERIAL_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "sw/device/lib/usbdev.h"
-
-// This is only here because caller of _init needs it
-typedef struct usb_ss_ctx {
-  void *ctx;
-  int ep;
-  int cur_buf;
-  int cur_cpos;
-  union usb_ss_b2w {
-    uint32_t data_w;
-    uint8_t data_b[4];
-  } chold;
-  void (*got_byte)(uint8_t);
-} usb_ss_ctx_t;
-
-/**
- * Send a byte on a simpleserial endpoint
- *
- * @param ssctx instance context
- * @param c byte to send
- */
-void usb_simpleserial_send_byte(usb_ss_ctx_t *ssctx, uint8_t c);
-
-/**
- * Initialize a simpleserial endpoint
- *
- * @param ssctx unintialized simpleserial instance context
- * @param ctx initialized usbdev context
- * @param ep endpoint number for this instance
- * @param got_byte callback function for when a byte is received
- */
-void usb_simpleserial_init(usb_ss_ctx_t *ssctx, usbdev_ctx_t *ctx, int ep,
-                           void (*got_byte)(uint8_t));
-
-#endif  // OPENTITAN_SW_DEVICE_LIB_USB_SIMPLESERIAL_H_
diff --git a/sw/device/lib/usbdev.c b/sw/device/lib/usbdev.c
deleted file mode 100644
index f948458..0000000
--- a/sw/device/lib/usbdev.c
+++ /dev/null
@@ -1,382 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-
-#include "sw/device/lib/usbdev.h"
-
-#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
-#include "usbdev_regs.h"  // Generated.
-
-#define USBDEV_BASE_ADDR TOP_EARLGREY_USBDEV_BASE_ADDR
-
-#define EXTRACT(n, f) ((n >> USBDEV_##f##_OFFSET) & USBDEV_##f##_MASK)
-
-#define SETBIT(val, bit) (val | 1 << bit)
-#define CLRBIT(val, bit) (val & ~(1 << bit))
-
-#define REG32(add) *((volatile uint32_t *)(add))
-
-static bool endpoint_is_in(uint8_t endpoint) { return endpoint & 0x80; }
-
-static uint8_t endpoint_number(uint8_t endpoint) { return endpoint & 0x7F; }
-
-// Free buffer pool is held on a simple stack
-// Initalize to all buffer IDs are free
-static void buf_init(usbdev_ctx_t *ctx) {
-  for (int i = 0; i < NUM_BUFS; i++) {
-    ctx->freebuf[i] = i;
-  }
-  ctx->nfree = NUM_BUFS;
-}
-
-// Allocating a buffer just pops next ID from the stack
-usbbufid_t usbdev_buf_allocate_byid(usbdev_ctx_t *ctx) {
-  if (ctx->nfree <= 0) {
-    return -1;
-  }
-  return ctx->freebuf[--ctx->nfree];
-}
-
-// Freeing a buffer just pushes the ID back on the stack
-int usbdev_buf_free_byid(usbdev_ctx_t *ctx, usbbufid_t buf) {
-  if ((ctx->nfree >= NUM_BUFS) || (buf >= NUM_BUFS)) {
-    return -1;
-  }
-  ctx->freebuf[ctx->nfree++] = buf;
-  return 0;
-}
-
-uint32_t *usbdev_buf_idtoaddr(usbdev_ctx_t *ctx, usbbufid_t buf) {
-  return (uint32_t *)(USBDEV_BASE_ADDR + USBDEV_BUFFER_REG_OFFSET +
-                      (buf * BUF_LENGTH));
-}
-
-void usbdev_buf_copyto_byid(usbdev_ctx_t *ctx, usbbufid_t buf, const void *from,
-                            size_t len_bytes) {
-  int32_t *from_word = (int32_t *)from;
-  int len_words;
-  volatile uint32_t *bp = usbdev_buf_idtoaddr(ctx, buf);
-
-  if (len_bytes > BUF_LENGTH) {
-    len_bytes = BUF_LENGTH;
-  }
-  // This will round up if len_bytes is not on a multiple of int32_t
-  // Always ok to fill the extra bytes since the buffers are aligned
-  len_words = (len_bytes + sizeof(int32_t) - 1) / sizeof(int32_t);
-  for (int i = 0; i < len_words; i++) {
-    bp[i] = from_word[i];
-  }
-}
-
-// Supply as many buffers to the receive available fifo as possible
-inline static void fill_av_fifo(usbdev_ctx_t *ctx) {
-  while (!(REG32(USBDEV_BASE_ADDR + USBDEV_USBSTAT_REG_OFFSET) &
-           (1 << USBDEV_USBSTAT_AV_FULL_BIT))) {
-    usbbufid_t buf = usbdev_buf_allocate_byid(ctx);
-    if (buf < 0) {
-      // no more free buffers, can't fill AV FIFO
-      break;
-    }
-    REG32(USBDEV_BASE_ADDR + USBDEV_AVBUFFER_REG_OFFSET) = buf;
-  }
-}
-
-void usbdev_sendbuf_byid(usbdev_ctx_t *ctx, usbbufid_t buf, size_t size,
-                         int endpoint) {
-  uint32_t configin =
-      USBDEV_BASE_ADDR + USBDEV_CONFIGIN_0_REG_OFFSET + (4 * endpoint);
-
-  if ((endpoint >= NUM_ENDPOINTS) || (buf >= NUM_BUFS)) {
-    return;
-  }
-
-  if (size > BUF_LENGTH) {
-    size = BUF_LENGTH;
-  }
-
-  REG32(configin) = ((buf << USBDEV_CONFIGIN_0_BUFFER_0_OFFSET) |
-                     (size << USBDEV_CONFIGIN_0_SIZE_0_OFFSET) |
-                     (1 << USBDEV_CONFIGIN_0_RDY_0_BIT));
-}
-
-void usbdev_poll(usbdev_ctx_t *ctx) {
-  uint32_t istate = REG32(USBDEV_BASE_ADDR + USBDEV_INTR_STATE_REG_OFFSET);
-
-  // Do this first to keep things going
-  fill_av_fifo(ctx);
-
-  // Process IN completions first so we get the fact that send completed
-  // before processing a response
-  if (istate & (1 << USBDEV_INTR_STATE_PKT_SENT_BIT)) {
-    uint32_t sentep = REG32(USBDEV_BASE_ADDR + USBDEV_IN_SENT_REG_OFFSET);
-    uint32_t configin = USBDEV_BASE_ADDR + USBDEV_CONFIGIN_0_REG_OFFSET;
-    TRC_C('a' + sentep);
-    for (int ep = 0; ep < NUM_ENDPOINTS; ep++) {
-      if (sentep & (1 << ep)) {
-        // Free up the buffer and optionally callback
-        int32_t cfgin = REG32(configin + (4 * ep));
-        usbdev_buf_free_byid(ctx, EXTRACT(cfgin, CONFIGIN_0_BUFFER_0));
-        if (ctx->tx_done_callback[ep]) {
-          ctx->tx_done_callback[ep](ctx->ep_ctx[ep]);
-        }
-      }
-    }
-    // Write one to clear all the ones we handled
-    REG32(USBDEV_BASE_ADDR + USBDEV_IN_SENT_REG_OFFSET) = sentep;
-    // Clear the interupt
-    REG32(USBDEV_BASE_ADDR + USBDEV_INTR_STATE_REG_OFFSET) =
-        (1 << USBDEV_INTR_STATE_PKT_SENT_BIT);
-  }
-
-  if (istate & (1 << USBDEV_INTR_STATE_PKT_RECEIVED_BIT)) {
-    while (!(REG32(USBDEV_BASE_ADDR + USBDEV_USBSTAT_REG_OFFSET) &
-             (1 << USBDEV_USBSTAT_RX_EMPTY_BIT))) {
-      uint32_t rxinfo = REG32(USBDEV_BASE_ADDR + USBDEV_RXFIFO_REG_OFFSET);
-      usbbufid_t buf = EXTRACT(rxinfo, RXFIFO_BUFFER);
-      int size = EXTRACT(rxinfo, RXFIFO_SIZE);
-      int endpoint = EXTRACT(rxinfo, RXFIFO_EP);
-      int setup = (rxinfo >> USBDEV_RXFIFO_SETUP_BIT) & 1;
-
-      if (ctx->rx_callback[endpoint]) {
-        ctx->rx_callback[endpoint](ctx->ep_ctx[endpoint], buf, size, setup);
-      } else {
-        TRC_S("USB: unexpected RX ");
-        TRC_I(rxinfo, 24);
-      }
-      usbdev_buf_free_byid(ctx, buf);
-    }
-    // Clear the interupt
-    REG32(USBDEV_BASE_ADDR + USBDEV_INTR_STATE_REG_OFFSET) =
-        (1 << USBDEV_INTR_STATE_PKT_RECEIVED_BIT);
-  }
-  if (istate & ~((1 << USBDEV_INTR_STATE_PKT_RECEIVED_BIT) |
-                 (1 << USBDEV_INTR_STATE_PKT_SENT_BIT))) {
-    TRC_C('I');
-    TRC_I(istate, 12);
-    TRC_C(' ');
-    REG32(USBDEV_BASE_ADDR + USBDEV_INTR_STATE_REG_OFFSET) =
-        istate & ~((1 << USBDEV_INTR_STATE_PKT_RECEIVED_BIT) |
-                   (1 << USBDEV_INTR_STATE_PKT_SENT_BIT));
-    if (istate & (1 << USBDEV_INTR_ENABLE_LINK_RESET_BIT)) {
-      // Link reset
-      for (int ep = 0; ep < NUM_ENDPOINTS; ep++) {
-        if (ctx->reset[ep]) {
-          ctx->reset[ep](ctx->ep_ctx[ep]);
-        }
-      }
-
-      // Clear the interupt
-      REG32(USBDEV_BASE_ADDR + USBDEV_INTR_STATE_REG_OFFSET) =
-          (1 << USBDEV_INTR_ENABLE_LINK_RESET_BIT);
-    }
-  }
-  // TODO - clean this up
-  // Frame ticks every 1ms, use to flush data every 16ms
-  // (faster in DPI but this seems to work ok)
-  // At reset frame count is 0, compare to 1 so no calls before SOF received
-  uint32_t usbframe = EXTRACT(
-      REG32(USBDEV_BASE_ADDR + USBDEV_USBSTAT_REG_OFFSET), USBSTAT_FRAME);
-  if ((usbframe & 0xf) == 1) {
-    if (ctx->flushed == 0) {
-      for (int i = 0; i < NUM_ENDPOINTS; i++) {
-        if (ctx->flush[i]) {
-          ctx->flush[i](ctx->ep_ctx[i]);
-        }
-      }
-      ctx->flushed = 1;
-    }
-  } else {
-    ctx->flushed = 0;
-  }
-  // TODO Errors? What Errors?
-}
-
-unsigned int usbdev_get_status(usbdev_ctx_t *ctx) {
-  unsigned int status = REG32(USBDEV_BASE_ADDR + USBDEV_USBSTAT_REG_OFFSET);
-  return status;
-}
-
-unsigned int usbdev_get_link_state(usbdev_ctx_t *ctx) {
-  unsigned int link_state = EXTRACT(
-      REG32(USBDEV_BASE_ADDR + USBDEV_USBSTAT_REG_OFFSET), USBSTAT_LINK_STATE);
-  return link_state;
-}
-
-unsigned int usbdev_get_address(usbdev_ctx_t *ctx) {
-  unsigned int addr =
-      EXTRACT(REG32(USBDEV_BASE_ADDR + USBDEV_USBCTRL_REG_OFFSET),
-              USBCTRL_DEVICE_ADDRESS);
-  return addr;
-}
-
-void usbdev_set_deviceid(usbdev_ctx_t *ctx, int deviceid) {
-  REG32(USBDEV_BASE_ADDR + USBDEV_USBCTRL_REG_OFFSET) =
-      (1 << USBDEV_USBCTRL_ENABLE_BIT) |
-      (deviceid << USBDEV_USBCTRL_DEVICE_ADDRESS_OFFSET);
-}
-
-void usbdev_halt(usbdev_ctx_t *ctx, int endpoint, int enable) {
-  uint32_t reg_offset = endpoint_is_in(endpoint) ? USBDEV_IN_STALL_REG_OFFSET
-                                                 : USBDEV_OUT_STALL_REG_OFFSET;
-  uint32_t epbit = 1 << endpoint_number(endpoint);
-  uint32_t stall = REG32(USBDEV_BASE_ADDR + reg_offset);
-  if (enable) {
-    stall |= epbit;
-  } else {
-    stall &= ~epbit;
-  }
-  REG32(USBDEV_BASE_ADDR + reg_offset) = stall;
-  ctx->halted = stall;
-  // TODO future addition would be to callback the endpoint driver
-  // for now it just sees its traffic has stopped
-}
-
-void usbdev_set_iso(usbdev_ctx_t *ctx, int endpoint, int enable) {
-  uint32_t reg_offset;
-  uint32_t ep_number = endpoint_number(endpoint);
-  if (endpoint_is_in(endpoint)) {
-    reg_offset = USBDEV_IN_ISO_REG_OFFSET;
-  } else {
-    reg_offset = USBDEV_OUT_ISO_REG_OFFSET;
-  }
-  if (enable) {
-    REG32(USBDEV_BASE_ADDR + reg_offset) =
-        SETBIT(REG32(USBDEV_BASE_ADDR + reg_offset), ep_number);
-  } else {
-    REG32(USBDEV_BASE_ADDR + reg_offset) =
-        CLRBIT(REG32(USBDEV_BASE_ADDR + reg_offset), ep_number);
-  }
-}
-
-void usbdev_clear_data_toggle(usbdev_ctx_t *ctx, int endpoint) {
-  REG32(USBDEV_BASE_ADDR + USBDEV_DATA_TOGGLE_CLEAR_REG_OFFSET) =
-      (1 << endpoint);
-}
-
-void usbdev_set_ep0_stall(usbdev_ctx_t *ctx, int stall) {
-  if (stall) {
-    REG32(USBDEV_BASE_ADDR + USBDEV_IN_STALL_REG_OFFSET) =
-        REG32(USBDEV_BASE_ADDR + USBDEV_IN_STALL_REG_OFFSET) | 1;
-    REG32(USBDEV_BASE_ADDR + USBDEV_OUT_STALL_REG_OFFSET) =
-        REG32(USBDEV_BASE_ADDR + USBDEV_OUT_STALL_REG_OFFSET) | 1;
-  } else {
-    REG32(USBDEV_BASE_ADDR + USBDEV_IN_STALL_REG_OFFSET) =
-        REG32(USBDEV_BASE_ADDR + USBDEV_IN_STALL_REG_OFFSET) & ~(1);
-    REG32(USBDEV_BASE_ADDR + USBDEV_OUT_STALL_REG_OFFSET) =
-        REG32(USBDEV_BASE_ADDR + USBDEV_OUT_STALL_REG_OFFSET) & ~(1);
-  }
-}
-
-void usbdev_clear_out_nak(usbdev_ctx_t *ctx, int ep) {
-  uint32_t rxen = REG32(USBDEV_BASE_ADDR + USBDEV_RXENABLE_OUT_REG_OFFSET);
-  rxen |= (1 << (ep + USBDEV_RXENABLE_OUT_OUT_0_BIT));
-  REG32(USBDEV_BASE_ADDR + USBDEV_RXENABLE_OUT_REG_OFFSET) = rxen;
-}
-
-// TODO got hang with this inline
-int usbdev_can_rem_wake(usbdev_ctx_t *ctx) { return ctx->can_wake; }
-
-void usbdev_endpoint_setup(usbdev_ctx_t *ctx, int ep,
-                           usbdev_out_transfer_mode_t out_mode, void *ep_ctx,
-                           void (*tx_done)(void *),
-                           void (*rx)(void *, usbbufid_t, int, int),
-                           void (*flush)(void *), void (*reset)(void *)) {
-  ctx->ep_ctx[ep] = ep_ctx;
-  ctx->tx_done_callback[ep] = tx_done;
-  ctx->rx_callback[ep] = rx;
-  ctx->flush[ep] = flush;
-  ctx->reset[ep] = reset;
-
-  uint32_t tx_ep_en = REG32(USBDEV_BASE_ADDR + USBDEV_EP_IN_ENABLE_REG_OFFSET);
-  tx_ep_en |= (1 << (ep + USBDEV_EP_IN_ENABLE_ENABLE_0_BIT));
-  REG32(USBDEV_BASE_ADDR + USBDEV_EP_IN_ENABLE_REG_OFFSET) = tx_ep_en;
-
-  if (out_mode != kUsbdevOutDisabled) {
-    uint32_t rxen = REG32(USBDEV_BASE_ADDR + USBDEV_RXENABLE_OUT_REG_OFFSET);
-    rxen |= (1 << (ep + USBDEV_RXENABLE_OUT_OUT_0_BIT));
-    REG32(USBDEV_BASE_ADDR + USBDEV_RXENABLE_OUT_REG_OFFSET) = rxen;
-    uint32_t ep_en = REG32(USBDEV_BASE_ADDR + USBDEV_EP_OUT_ENABLE_REG_OFFSET);
-    ep_en |= (1 << (ep + USBDEV_EP_OUT_ENABLE_ENABLE_0_BIT));
-    REG32(USBDEV_BASE_ADDR + USBDEV_EP_OUT_ENABLE_REG_OFFSET) = ep_en;
-  }
-  if (out_mode == kUsbdevOutMessage) {
-    uint32_t set_nak_out =
-        REG32(USBDEV_BASE_ADDR + USBDEV_SET_NAK_OUT_REG_OFFSET);
-    set_nak_out |= (1 << (ep + USBDEV_SET_NAK_OUT_ENABLE_0_BIT));
-    REG32(USBDEV_BASE_ADDR + USBDEV_SET_NAK_OUT_REG_OFFSET) = set_nak_out;
-  }
-}
-
-void usbdev_connect(usbdev_ctx_t *ctx) {
-  REG32(USBDEV_BASE_ADDR + USBDEV_USBCTRL_REG_OFFSET) =
-      (1 << USBDEV_USBCTRL_ENABLE_BIT);
-}
-
-void usbdev_init(usbdev_ctx_t *ctx, bool pinflip, bool en_diff_rcvr,
-                 bool tx_use_d_se0) {
-  // setup context
-  for (int i = 0; i < NUM_ENDPOINTS; i++) {
-    usbdev_endpoint_setup(ctx, i, kUsbdevOutDisabled, NULL, NULL, NULL, NULL,
-                          NULL);
-  }
-  ctx->halted = 0;
-  ctx->can_wake = 0;
-  buf_init(ctx);
-
-  // All about polling...
-  REG32(USBDEV_BASE_ADDR + USBDEV_INTR_ENABLE_REG_OFFSET) = 0;
-
-  // Provide buffers for any reception
-  fill_av_fifo(ctx);
-
-  REG32(USBDEV_BASE_ADDR + USBDEV_RXENABLE_SETUP_REG_OFFSET) =
-      (1 << USBDEV_RXENABLE_SETUP_SETUP_0_BIT);
-  REG32(USBDEV_BASE_ADDR + USBDEV_RXENABLE_OUT_REG_OFFSET) =
-      (1 << USBDEV_RXENABLE_OUT_OUT_0_BIT);
-  REG32(USBDEV_BASE_ADDR + USBDEV_EP_IN_ENABLE_REG_OFFSET) =
-      (1 << USBDEV_EP_IN_ENABLE_ENABLE_0_BIT);
-  REG32(USBDEV_BASE_ADDR + USBDEV_EP_OUT_ENABLE_REG_OFFSET) =
-      (1 << USBDEV_EP_OUT_ENABLE_ENABLE_0_BIT);
-  REG32(USBDEV_BASE_ADDR + USBDEV_IN_STALL_REG_OFFSET) = 0;
-  REG32(USBDEV_BASE_ADDR + USBDEV_OUT_STALL_REG_OFFSET) = 0;
-
-  uint32_t phy_config = (pinflip << USBDEV_PHY_CONFIG_PINFLIP_BIT) |
-                        (en_diff_rcvr << USBDEV_PHY_CONFIG_USE_DIFF_RCVR_BIT) |
-                        (tx_use_d_se0 << USBDEV_PHY_CONFIG_TX_USE_D_SE0_BIT) |
-                        (1 << USBDEV_PHY_CONFIG_EOP_SINGLE_BIT_BIT);
-  REG32(USBDEV_BASE_ADDR + USBDEV_PHY_CONFIG_REG_OFFSET) = phy_config;
-}
-
-void usbdev_force_dx_pullup(line_sel_t line, bool set) {
-  // Force usb to pretend it is in suspend
-  uint32_t reg_val = REG32(USBDEV_BASE_ADDR + USBDEV_PHY_PINS_DRIVE_REG_OFFSET);
-  uint32_t mask;
-
-  mask = line == kDpSel ? USBDEV_PHY_PINS_DRIVE_DP_PULLUP_EN_O_BIT
-                        : USBDEV_PHY_PINS_DRIVE_DN_PULLUP_EN_O_BIT;
-
-  if (set) {
-    reg_val = SETBIT(reg_val, mask);
-  } else {
-    reg_val = CLRBIT(reg_val, mask);
-  }
-
-  reg_val = SETBIT(reg_val, USBDEV_PHY_PINS_DRIVE_EN_BIT);
-  REG32(USBDEV_BASE_ADDR + USBDEV_PHY_PINS_DRIVE_REG_OFFSET) = reg_val;
-}
-
-void usbdev_set_wake_module_active(bool set) {
-  uint32_t reg_val = REG32(USBDEV_BASE_ADDR + USBDEV_WAKE_CONTROL_REG_OFFSET);
-  if (set) {
-    reg_val = SETBIT(reg_val, USBDEV_WAKE_CONTROL_SUSPEND_REQ_BIT);
-  } else {
-    reg_val = SETBIT(reg_val, USBDEV_WAKE_CONTROL_WAKE_ACK_BIT);
-  }
-  REG32(USBDEV_BASE_ADDR + USBDEV_WAKE_CONTROL_REG_OFFSET) = reg_val;
-}
-
-// `extern` declarations to give the inline functions in the
-// corresponding header a link location.
-
-extern int usbdev_halted(usbdev_ctx_t *ctx, int endpoint);
-extern void usbdev_rem_wake_en(usbdev_ctx_t *ctx, int enable);
diff --git a/sw/device/lib/usbdev.h b/sw/device/lib/usbdev.h
deleted file mode 100644
index 28edf82..0000000
--- a/sw/device/lib/usbdev.h
+++ /dev/null
@@ -1,310 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-
-#ifndef OPENTITAN_SW_DEVICE_LIB_USBDEV_H_
-#define OPENTITAN_SW_DEVICE_LIB_USBDEV_H_
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-
-// Hardware parameters
-#define NUM_BUFS 32
-#define BUF_LENGTH 64
-#define NUM_ENDPOINTS 12
-
-// USB buffers are held in the SRAM in the interface, referenced by ID
-// Buffer IDs are 0 to NUM_BUFS
-// Use negative buffer ID for error
-typedef int usbbufid_t;
-typedef struct usbdev_ctx usbdev_ctx_t;
-
-// Note: this is only needed here because the caller of init needs it
-struct usbdev_ctx {
-  // TODO: base_addr goes here once header files support using it
-  int can_wake;
-  uint8_t freebuf[NUM_BUFS];
-  uint32_t halted;  // bit vector per endpoint
-  int nfree;
-  int flushed;
-  usbdev_ctx_t *ep_ctx[NUM_ENDPOINTS];
-  void (*tx_done_callback[NUM_ENDPOINTS])(void *);
-  void (*rx_callback[NUM_ENDPOINTS])(void *, usbbufid_t, int, int);
-  void (*flush[NUM_ENDPOINTS])(void *);
-  void (*reset[NUM_ENDPOINTS])(void *);
-};
-
-/**
- * Select USB lines P or N
- */
-typedef enum line_sel { kDpSel = 0, kDnSel = 1 } line_sel_t;
-
-/**
- * Allocate a buffer for the caller to use
- *
- * @param ctx usbdev context pointer
- * @return buffer ID or negative for out of buffer error
- */
-usbbufid_t usbdev_buf_allocate_byid(usbdev_ctx_t *ctx);
-
-/**
- * Free a buffer when caller no longer needs it
- *
- * @param ctx usbdev context pointer
- * @param buf buffer ID being returned to free pool
- * @return 0 or -1 if the free pool is full (shouldn't happen)
- */
-int usbdev_buf_free_byid(usbdev_ctx_t *ctx, usbbufid_t buf);
-
-/**
- * Get memory address for accessing data in a buffer
- *
- * Hardware restriction: buffer can only be written with 32-bit words
- * Ok to cast the return value to int8_t * for reading
- *
- * @param ctx usbdev context pointer
- * @param buf buffer ID to access
- * @return pointer to access the data of @p buf
- */
-uint32_t *usbdev_buf_idtoaddr(usbdev_ctx_t *ctx, usbbufid_t buf);
-
-/**
- * Copy from memory into a buffer, referencing by buffer ID
- *
- * Implementation restriction: from must be 4-byte aligned
- * TODO remove restriction
- *
- * @param ctx usbdev context pointer
- * @param buf buffer ID to copy to
- * @param from source address for data
- * @param len_bytes length in bytes of data to copy
- */
-void usbdev_buf_copyto_byid(usbdev_ctx_t *ctx, usbbufid_t buf, const void *from,
-                            size_t len_bytes);
-
-/**
- * Schedule a buffer for transmission on an endpoint
- *
- * Send happens on next IN request for that endpoint from the host.
- * Once this call is made the buffer is owned by the hardware
- *
- * @param ctx usbdev context pointer
- * @param buf buffer ID to send
- * @param size length in bytes of data to send, zero is valid (used as ack)
- * @param endpoint endpoint to send from
- */
-void usbdev_sendbuf_byid(usbdev_ctx_t *ctx, usbbufid_t buf, size_t size,
-                         int endpoint);
-
-/**
- * Call regularly to poll the usbdev interface
- *
- * @param ctx usbdev context pointer
- */
-void usbdev_poll(usbdev_ctx_t *ctx);
-
-/**
- * Get the content of the USB status register
- * @param ctx usbdev context pointer
- * @return USB status register
- */
-unsigned int usbdev_get_status(usbdev_ctx_t *ctx);
-
-/**
- * Get the current USB link state
- * @param ctx usbdev context pointer
- * @return USB link state
- */
-unsigned int usbdev_get_link_state(usbdev_ctx_t *ctx);
-
-/**
- * Get the current USB address
- * @param ctx usbdev context pointer
- * @return USB address
- */
-unsigned int usbdev_get_address(usbdev_ctx_t *ctx);
-
-/**
- * Set the USB device ID
- *
- * Device ID must be zero at init. When the host assigns an ID
- * with a SET_ADDRESS packet and the complete SETUP transaction is
- * complete, this function should be called to set the new ID. Note
- * on a reset the hardware will clear the device ID back to 0.
- *
- * @param ctx usbdev context pointer
- * @param deviceid new deviceid
- */
-void usbdev_set_deviceid(usbdev_ctx_t *ctx, int deviceid);
-
-/**
- * Halt or release an endpoint
- *
- * By default endpoints are enabled, but they can be halted but the host
- *
- * @param ctx usbdev context pointer
- * @param endpoint number
- * @param enable set/clear
- */
-void usbdev_halt(usbdev_ctx_t *ctx, int endpoint, int enable);
-
-/**
- * Get halted status for an endpoint
- *
- * @param ctx usbdev context pointer
- * @param endpoint number
- * @return 1 if endpoint is halted else 0
- */
-inline int usbdev_halted(usbdev_ctx_t *ctx, int endpoint) {
-  return (ctx->halted >> endpoint) & 0x1;
-}
-
-/**
- * Configure an endpoint as ISO / non-ISO
- *
- * By default endpoints are non-ISO, but they can be set to ISO
- *
- * @param ctx usbdev context pointer
- * @param endpoint number
- * @param enable 0: non-ISO, 1: ISO
- */
-void usbdev_set_iso(usbdev_ctx_t *ctx, int endpoint, int enable);
-
-/**
- * Clear the data toggle bit for an endpoint
- * @param ctx usbdev context pointer
- * @param endpoint Endpoint number
- */
-void usbdev_clear_data_toggle(usbdev_ctx_t *ctx, int endpoint);
-
-/**
- * Updates the stall setting for EP0. If stall is set then an IN, or
- * OUT transaction to EP0 will be responded to with a STALL return. This
- * flag is cleared on a a SETUP transaction
- * @param ctx usbdev context pointer
- * @param stall
- */
-void usbdev_set_ep0_stall(usbdev_ctx_t *ctx, int stall);
-
-/**
- * Enable or disable remote wake
- *
- * @param ctx usbdev context pointer
- * @param enable set/clear
- */
-inline void usbdev_rem_wake_en(usbdev_ctx_t *ctx, int enable) {
-  ctx->can_wake = (enable) ? 1 : 0;
-}
-
-/**
- * Get ability to wake the host
- *
- * @param ctx usbdev context pointer
- * @return 1 if remote wake is permitted else 0
- */
-int usbdev_can_rem_wake(usbdev_ctx_t *ctx);
-
-/**
- * Re-enable OUT transactions for a given endpoint.
- *
- * This function must be called after reception of a packet for a given
- * endpoint, else the endpoint will NAK the next packet.
- *
- * @param ctx usbdev context pointer
- * @param endpoint endpoint number
- */
-void usbdev_clear_out_nak(usbdev_ctx_t *ctx, int ep);
-
-typedef enum usbdev_out_transfer_mode {
-  /**
-   * The endpoint does not support OUT transactions.
-   */
-  kUsbdevOutDisabled = 0,
-  /**
-   * Software does NOT need to call usbdev_clear_out_nak() after every received
-   * transaction. If software takes no action, usbdev will allow an endpoint's
-   * transactions to proceed as long as a buffer is available.
-   */
-  kUsbdevOutStream = 1,
-  /**
-   * Software must call usbdev_clear_out_nak() after every received transaction
-   * to re-enable packet reception. This gives software time to respond with the
-   * appropriate handshake when it's ready.
-   */
-  kUsbdevOutMessage = 2,
-} usbdev_out_transfer_mode_t;
-
-/**
- * Call to setup an endpoint
- *
- * @param ctx usbdev context pointer
- * @param ep endpoint number
- * @param out_mode the transfer mode for OUT transactions
- * @param ep_ctx context pointer for callee
- * @param tx_done(void *ep_ctx) callback once send has been Acked
- * @param rx(void *ep_ctx, usbbufid_t buf, int size, int setup)
-          called when a packet is received
- * @param flush(void *ep_ctx) called every 16ms based USB host timebase
- * @param reset(void *ep_ctx) called when an USB link reset is detected
- */
-void usbdev_endpoint_setup(usbdev_ctx_t *ctx, int ep,
-                           usbdev_out_transfer_mode_t out_mode, void *ep_ctx,
-                           void (*tx_done)(void *),
-                           void (*rx)(void *, usbbufid_t, int, int),
-                           void (*flush)(void *), void (*reset)(void *));
-
-/**
- * Connect the device to the bus.
- *
- * @param ctx the usbdev context.
- */
-void usbdev_connect(usbdev_ctx_t *ctx);
-
-/**
- * Initialize the usbdev interface
- *
- * Does not connect the device, since the default endpoint is not yet enabled.
- * See usbdev_connect().
- *
- * @param ctx uninitialized usbdev context pointer
- * @param pinflip boolean to indicate if PHY should be configured for D+/D- flip
- * @param en_diff_rcvr boolean to indicate if PHY should enable an external
- *                     differential receiver, activating the single-ended D
- *                     input
- * @param tx_use_d_se0 boolean to indicate if PHY uses D/SE0 for TX instead of
- *                     Dp/Dn
- */
-void usbdev_init(usbdev_ctx_t *ctx, bool pinflip, bool en_diff_rcvr,
-                 bool tx_use_d_se0);
-
-/**
- * Force usbdev to output suspend state for testing purposes
- */
-void usbdev_force_suspend(void);
-
-/**
- * Force usbdev pull-up to specific value
- */
-void usbdev_force_dx_pullup(line_sel_t line, bool set);
-
-/**
- * Enable usb wake module to go active / inactive.
- */
-void usbdev_set_wake_module_active(bool set);
-
-// Used for tracing what is going on. This may impact timing which is critical
-// when simulating with the USB DPI module.
-//#define ENABLE_TRC
-#ifdef ENABLE_TRC
-#include "sw/device/lib/runtime/log.h"
-#define TRC_S(s) LOG_INFO("%s", s)
-#define TRC_I(i, b) LOG_INFO("0x%x", i)
-#define TRC_C(c) LOG_INFO("%c", c)
-#else
-#define TRC_S(s)
-#define TRC_I(i, b)
-#define TRC_C(c)
-#endif
-
-#endif  // OPENTITAN_SW_DEVICE_LIB_USBDEV_H_
diff --git a/sw/device/tests/BUILD b/sw/device/tests/BUILD
index 45e46ec..d00bc5a 100644
--- a/sw/device/tests/BUILD
+++ b/sw/device/tests/BUILD
@@ -1257,12 +1257,12 @@
     targets = ["verilator"],
     deps = [
         "//hw/top_earlgrey/sw/autogen:top_earlgrey",
-        "//sw/device/lib:usb",
-        "//sw/device/lib:usb_simpleserial",
         "//sw/device/lib/dif:pinmux",
         "//sw/device/lib/runtime:log",
         "//sw/device/lib/runtime:print",
         "//sw/device/lib/testing:pinmux_testutils",
+        "//sw/device/lib/testing:usb_testutils",
+        "//sw/device/lib/testing:usb_testutils_simpleserial",
         "//sw/device/lib/testing/test_framework:ottf_main",
     ],
 )
diff --git a/sw/device/tests/sim_dv/BUILD b/sw/device/tests/sim_dv/BUILD
index d52fa40..3a1f053 100644
--- a/sw/device/tests/sim_dv/BUILD
+++ b/sw/device/tests/sim_dv/BUILD
@@ -447,9 +447,9 @@
     srcs = ["pwrmgr_usbdev_smoketest.c"],
     targets = ["dv"],
     deps = [
-        "//sw/device/lib:usb",
         "//sw/device/lib/base:mmio",
         "//sw/device/lib/dif:pwrmgr",
+        "//sw/device/lib/dif:usbdev",
         "//sw/device/lib/runtime:hart",
         "//sw/device/lib/runtime:log",
         "//sw/device/lib/testing:pwrmgr_testutils",
@@ -583,13 +583,13 @@
         "//hw/top_earlgrey/ip/pwrmgr/data/autogen:pwrmgr_regs",
         "//hw/top_earlgrey/sw/autogen:top_earlgrey",
         "//sw/device/lib:irq",
-        "//sw/device/lib:usb",
         "//sw/device/lib/base:mmio",
         "//sw/device/lib/dif:adc_ctrl",
         "//sw/device/lib/dif:pinmux",
         "//sw/device/lib/dif:pwrmgr",
         "//sw/device/lib/dif:rv_plic",
         "//sw/device/lib/dif:sensor_ctrl",
+        "//sw/device/lib/dif:usbdev",
         "//sw/device/lib/runtime:ibex",
         "//sw/device/lib/runtime:log",
         "//sw/device/lib/testing:aon_timer_testutils",
@@ -608,12 +608,12 @@
         "//hw/top_earlgrey/ip/pwrmgr/data/autogen:pwrmgr_regs",
         "//hw/top_earlgrey/sw/autogen:top_earlgrey",
         "//sw/device/lib:irq",
-        "//sw/device/lib:usb",
         "//sw/device/lib/base:mmio",
         "//sw/device/lib/dif:adc_ctrl",
         "//sw/device/lib/dif:pinmux",
         "//sw/device/lib/dif:pwrmgr",
         "//sw/device/lib/dif:rv_plic",
+        "//sw/device/lib/dif:usbdev",
         "//sw/device/lib/runtime:ibex",
         "//sw/device/lib/runtime:log",
         "//sw/device/lib/testing:aon_timer_testutils",
diff --git a/sw/device/tests/sim_dv/pwrmgr_deep_sleep_all_wake_ups.c b/sw/device/tests/sim_dv/pwrmgr_deep_sleep_all_wake_ups.c
index b499c9a..223863d 100644
--- a/sw/device/tests/sim_dv/pwrmgr_deep_sleep_all_wake_ups.c
+++ b/sw/device/tests/sim_dv/pwrmgr_deep_sleep_all_wake_ups.c
@@ -8,6 +8,7 @@
 #include "sw/device/lib/dif/dif_pwrmgr.h"
 #include "sw/device/lib/dif/dif_rv_plic.h"
 #include "sw/device/lib/dif/dif_sysrst_ctrl.h"
+#include "sw/device/lib/dif/dif_usbdev.h"
 #include "sw/device/lib/irq.h"
 #include "sw/device/lib/runtime/ibex.h"
 #include "sw/device/lib/runtime/log.h"
@@ -16,7 +17,6 @@
 #include "sw/device/lib/testing/rv_plic_testutils.h"
 #include "sw/device/lib/testing/test_framework/check.h"
 #include "sw/device/lib/testing/test_framework/ottf_main.h"
-#include "sw/device/lib/usbdev.h"
 
 #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
 #include "pwrmgr_regs.h"
@@ -147,14 +147,15 @@
 /**
  * Program usb config for test #4.
  * . Fake low power entry through usb.
- * . Force usb to output suspend indication.
- *   (*dif) handle is not used but leave as is
- *   to be called from execute_test.
+ * . Force wake detection module active.
  */
 static void prgm_usb_wakeup(void *dif) {
-  usbdev_set_wake_module_active(true);
-  usbdev_force_dx_pullup(kDpSel, true);
-  usbdev_force_dx_pullup(kDnSel, false);
+  dif_usbdev_phy_pins_drive_t pins = {
+      .dp_pullup_en = true,
+      .dn_pullup_en = false,
+  };
+  CHECK_DIF_OK(dif_usbdev_set_phy_pins_state(dif, kDifToggleEnabled, pins));
+  CHECK_DIF_OK(dif_usbdev_set_wake_enable(dif, kDifToggleEnabled));
 
   // Give the hardware a chance to recognize the wakeup values are the same.
   busy_spin_micros(20);
@@ -310,7 +311,7 @@
     LOG_INFO("Woke up by source %d", PWRMGR_PARAM_PINMUX_AON_USB_WKUP_REQ_IDX);
 
     // Turn off wake up.
-    usbdev_set_wake_module_active(false);
+    CHECK_DIF_OK(dif_usbdev_set_wake_enable(&usbdev, kDifToggleDisabled));
     CHECK_DIF_OK(dif_pinmux_wakeup_cause_clear(&pinmux));
     delay_n_clear(30);
     execute_test(PWRMGR_PARAM_AON_TIMER_AON_WKUP_REQ_IDX);
diff --git a/sw/device/tests/sim_dv/pwrmgr_normal_sleep_all_wake_ups.c b/sw/device/tests/sim_dv/pwrmgr_normal_sleep_all_wake_ups.c
index 96ceb6a..4a25baf 100644
--- a/sw/device/tests/sim_dv/pwrmgr_normal_sleep_all_wake_ups.c
+++ b/sw/device/tests/sim_dv/pwrmgr_normal_sleep_all_wake_ups.c
@@ -9,6 +9,7 @@
 #include "sw/device/lib/dif/dif_rv_plic.h"
 #include "sw/device/lib/dif/dif_sensor_ctrl.h"
 #include "sw/device/lib/dif/dif_sysrst_ctrl.h"
+#include "sw/device/lib/dif/dif_usbdev.h"
 #include "sw/device/lib/irq.h"
 #include "sw/device/lib/runtime/ibex.h"
 #include "sw/device/lib/runtime/log.h"
@@ -17,7 +18,6 @@
 #include "sw/device/lib/testing/rv_plic_testutils.h"
 #include "sw/device/lib/testing/test_framework/check.h"
 #include "sw/device/lib/testing/test_framework/ottf_main.h"
-#include "sw/device/lib/usbdev.h"
 
 #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
 #include "pwrmgr_regs.h"
@@ -154,9 +154,12 @@
  * to be called from execute_test
  */
 static void prgm_usb_wakeup(void *dif) {
-  usbdev_set_wake_module_active(true);
-  usbdev_force_dx_pullup(kDpSel, true);
-  usbdev_force_dx_pullup(kDnSel, false);
+  dif_usbdev_phy_pins_drive_t pins = {
+      .dp_pullup_en = true,
+      .dn_pullup_en = false,
+  };
+  CHECK_DIF_OK(dif_usbdev_set_phy_pins_state(dif, kDifToggleEnabled, pins));
+  CHECK_DIF_OK(dif_usbdev_set_wake_enable(dif, kDifToggleEnabled));
 
   LOG_INFO("prgm_usb_wakeup: wait 20us (usb)");
   // Give the hardware a chance to recognize the wakeup values are the same.
@@ -277,7 +280,7 @@
       CHECK_DIF_OK(dif_pinmux_wakeup_cause_clear(&pinmux));
       break;
     case PWRMGR_PARAM_PINMUX_AON_USB_WKUP_REQ_IDX:
-      usbdev_set_wake_module_active(false);
+      CHECK_DIF_OK(dif_usbdev_set_wake_enable(&usbdev, kDifToggleDisabled));
       CHECK_DIF_OK(dif_pinmux_wakeup_cause_clear(&pinmux));
       break;
     case PWRMGR_PARAM_AON_TIMER_AON_WKUP_REQ_IDX:
diff --git a/sw/device/tests/sim_dv/pwrmgr_usbdev_smoketest.c b/sw/device/tests/sim_dv/pwrmgr_usbdev_smoketest.c
index 4809787..c17e963 100644
--- a/sw/device/tests/sim_dv/pwrmgr_usbdev_smoketest.c
+++ b/sw/device/tests/sim_dv/pwrmgr_usbdev_smoketest.c
@@ -14,16 +14,17 @@
 
 #include "sw/device/lib/base/mmio.h"
 #include "sw/device/lib/dif/dif_pwrmgr.h"
+#include "sw/device/lib/dif/dif_usbdev.h"
 #include "sw/device/lib/runtime/hart.h"
 #include "sw/device/lib/runtime/log.h"
 #include "sw/device/lib/testing/pwrmgr_testutils.h"
 #include "sw/device/lib/testing/test_framework/check.h"
 #include "sw/device/lib/testing/test_framework/ottf_main.h"
-#include "sw/device/lib/usbdev.h"
 
 #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
 
 static dif_pwrmgr_t pwrmgr;
+static dif_usbdev_t usbdev;
 
 OTTF_DEFINE_TEST_CONFIG();
 
@@ -35,6 +36,8 @@
 bool test_main(void) {
   CHECK_DIF_OK(dif_pwrmgr_init(
       mmio_region_from_addr(TOP_EARLGREY_PWRMGR_AON_BASE_ADDR), &pwrmgr));
+  CHECK_DIF_OK(dif_usbdev_init(
+      mmio_region_from_addr(TOP_EARLGREY_USBDEV_BASE_ADDR), &usbdev));
 
   // Assuming the chip hasn't slept yet, wakeup reason should be empty.
   dif_pwrmgr_wakeup_reason_t wakeup_reason;
@@ -63,11 +66,16 @@
   }
 
   // Fake low power entry through usb
-  // Force usb to output suspend indication
+  // Force wake detection module active
   if (!low_power_exit) {
-    usbdev_set_wake_module_active(true);
-    usbdev_force_dx_pullup(kDpSel, true);
-    usbdev_force_dx_pullup(kDnSel, false);
+    CHECK_DIF_OK(dif_usbdev_set_wake_enable(&usbdev, kDifToggleDisabled));
+    dif_usbdev_phy_pins_drive_t pins = {
+        .dp_pullup_en = true,
+        .dn_pullup_en = false,
+    };
+    CHECK_DIF_OK(
+        dif_usbdev_set_phy_pins_state(&usbdev, kDifToggleEnabled, pins));
+    CHECK_DIF_OK(dif_usbdev_set_wake_enable(&usbdev, kDifToggleEnabled));
 
     // give the hardware a chance to recognize the wakeup values are the same
     busy_spin_micros(20);  // 20us
diff --git a/sw/device/tests/usbdev_test.c b/sw/device/tests/usbdev_test.c
index b53da0b..346fe2b 100644
--- a/sw/device/tests/usbdev_test.c
+++ b/sw/device/tests/usbdev_test.c
@@ -17,16 +17,15 @@
 // transactions with a data payload of "Hi!" to Endpoint 1. If these two OUT
 // transactions are succesfully received by the device, the test passes.
 
-#include "sw/device/lib/usbdev.h"
-
 #include "sw/device/lib/dif/dif_pinmux.h"
 #include "sw/device/lib/runtime/log.h"
 #include "sw/device/lib/runtime/print.h"
 #include "sw/device/lib/testing/pinmux_testutils.h"
 #include "sw/device/lib/testing/test_framework/check.h"
 #include "sw/device/lib/testing/test_framework/ottf_main.h"
-#include "sw/device/lib/usb_controlep.h"
-#include "sw/device/lib/usb_simpleserial.h"
+#include "sw/device/lib/testing/usb_testutils.h"
+#include "sw/device/lib/testing/usb_testutils_controlep.h"
+#include "sw/device/lib/testing/usb_testutils_simpleserial.h"
 
 #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"  // Generated.
 
@@ -48,9 +47,9 @@
 /**
  * USB device context types.
  */
-static usbdev_ctx_t usbdev;
-static usb_controlep_ctx_t usbdev_control;
-static usb_ss_ctx_t simple_serial;
+static usb_testutils_ctx_t usbdev;
+static usb_testutils_controlep_ctx_t usbdev_control;
+static usb_testutils_ss_ctx_t simple_serial;
 
 /**
  * Pinmux handle
@@ -108,17 +107,18 @@
   // Call `usbdev_init` here so that DPI will not start until the
   // simulation has finished all of the printing, which takes a while
   // if `--trace` was passed in.
-  usbdev_init(&usbdev, /* pinflip= */ false, /* en_diff_rcvr= */ false,
-              /* tx_use_d_se0= */ false);
-  usb_controlep_init(&usbdev_control, &usbdev, 0, config_descriptors,
-                     sizeof(config_descriptors));
-  while (usbdev_control.device_state != kUsbDeviceConfigured) {
-    usbdev_poll(&usbdev);
+  usb_testutils_init(&usbdev, /*pinflip=*/false, /*en_diff_rcvr=*/false,
+                     /*tx_use_d_se0=*/false);
+  usb_testutils_controlep_init(&usbdev_control, &usbdev, 0, config_descriptors,
+                               sizeof(config_descriptors));
+  while (usbdev_control.device_state != kUsbTestutilsDeviceConfigured) {
+    usb_testutils_poll(&usbdev);
   }
-  usb_simpleserial_init(&simple_serial, &usbdev, 1, usb_receipt_callback);
+  usb_testutils_simpleserial_init(&simple_serial, &usbdev, 1,
+                                  usb_receipt_callback);
 
   while (usb_chars_recved_total < kExpectedUsbCharsRecved) {
-    usbdev_poll(&usbdev);
+    usb_testutils_poll(&usbdev);
   }
 
   base_printf("\r\n");