Software APIs
usbdev_vbus_test.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 //
5 // USB VBUS test
6 //
7 // Checks for the presence of VBUS from the host/DPI model, optionally checking
8 // that VBUS is low initially when the test starts.
9 
10 #include <stdbool.h>
11 #include <stdint.h>
12 
13 #include "sw/device/lib/base/status.h"
18 #include "sw/device/lib/testing/pinmux_testutils.h"
19 #include "sw/device/lib/testing/test_framework/check.h"
21 
22 #define USBDEV_BASE_ADDR TOP_EARLGREY_USBDEV_BASE_ADDR
23 
24 /**
25  * Are we expecting VBUS to be low at the start of the test, ie. no connection
26  * to the physical host or the DPI model is inactive?
27  * Typically useful only for an FPGA target that is being manually supervised.
28  */
29 static const bool kCheckLowFirst = false;
30 
31 /**
32  * USB device handle
33  */
34 static dif_usbdev_t usbdev;
35 
36 /**
37  * Pinmux handle
38  */
39 static dif_pinmux_t pinmux;
40 
41 // Wait with timeout until the VBUS/SENSE signal is in the expected state.
42 static status_t vbus_wait(bool expected, uint32_t timeout_micros) {
43  ibex_timeout_t timeout = ibex_timeout_init(timeout_micros);
44  do {
45  // Read the current state of VBUS.
46  bool vbus;
47  TRY(dif_usbdev_status_get_sense(&usbdev, &vbus));
48  if (vbus == expected) {
49  return OK_STATUS();
50  }
51  } while (!ibex_timeout_check(&timeout));
52 
53  return DEADLINE_EXCEEDED();
54 }
55 
56 OTTF_DEFINE_TEST_CONFIG();
57 
58 bool test_main(void) {
59  uint32_t timeout_micros = 1000u;
60  bool prompt = false;
61 
62  switch (kDeviceType) {
63  // In simulation the DPI model connects VBUS shortly after reset.
64  case kDeviceSimDV:
66  timeout_micros = 1000u;
67  break;
68  default:
69  // FPGA platforms where user intervention may be required.
70  timeout_micros = 30 * 1000 * 1000u;
71  prompt = true;
72 
73  LOG_INFO("Running USBDEV_VBUS test");
74  break;
75  }
76 
77  // Ensure that the VBUS/SENSE signal is routed through to the usbdev
78  CHECK_DIF_OK(dif_pinmux_init(
80  pinmux_testutils_init(&pinmux);
81  CHECK_DIF_OK(dif_pinmux_input_select(
84 
85  CHECK_DIF_OK(
86  dif_usbdev_init(mmio_region_from_addr(USBDEV_BASE_ADDR), &usbdev));
87 
88  // Initially the VBUS may be expected to be low; if so, ensure that this is
89  // the case.
90  if (kCheckLowFirst) {
91  if (prompt) {
92  bool vbus;
93  CHECK_DIF_OK(dif_usbdev_status_get_sense(&usbdev, &vbus));
94  if (vbus) {
95  LOG_INFO("Disconnect or power down the USB");
96  }
97  }
98 
99  CHECK_STATUS_OK(vbus_wait(false, timeout_micros));
100 
101  if (prompt) {
102  LOG_INFO("Connect or power up the USB");
103  }
104  }
105 
106  // Check for VBUS present/risen.
107  CHECK_STATUS_OK(vbus_wait(true, timeout_micros));
108 
109  return true;
110 }