Software APIs
usbdev_aon_wake_reset_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 
10 #include "sw/device/lib/testing/pinmux_testutils.h"
11 #include "sw/device/lib/testing/test_framework/check.h"
13 #include "sw/device/lib/testing/usb_testutils.h"
14 #include "sw/device/lib/testing/usb_testutils_controlep.h"
15 
16 #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" // Generated.
17 
18 /**
19  * Configuration values for USB.
20  */
21 static const uint8_t config_descriptors[] = {
22  USB_CFG_DSCR_HEAD(USB_CFG_DSCR_LEN + USB_INTERFACE_DSCR_LEN, 1),
23  // Single interface with no endpoint, just to make the host happy.
24  VEND_INTERFACE_DSCR(0, 0, 0x50, 0),
25 };
26 
27 /**
28  * USB device context types.
29  */
30 static usb_testutils_ctx_t usbdev;
31 static usb_testutils_controlep_ctx_t usbdev_control;
32 
33 /**
34  * Pinmux handle
35  */
36 static dif_pinmux_t pinmux;
37 
38 OTTF_DEFINE_TEST_CONFIG();
39 
40 static void init_peripherals(void) {
41  CHECK_DIF_OK(dif_pinmux_init(
43  pinmux_testutils_init(&pinmux);
44  CHECK_DIF_OK(dif_pinmux_input_select(
47 
48  CHECK_STATUS_OK(usb_testutils_init(&usbdev, /*pinflip=*/false,
49  /*en_diff_rcvr=*/true,
50  /*tx_use_d_se0=*/false));
51  CHECK_STATUS_OK(usb_testutils_controlep_init(
52  &usbdev_control, &usbdev, 0, config_descriptors,
53  sizeof(config_descriptors), NULL, 0));
54 }
55 
56 // Enable/disable the AON Wake module, and wait with timeout until that has
57 // been confirmed.
58 static status_t aon_wait(dif_toggle_t enable) {
59  // We must be sure that any alteration to the USBDEV pull up enables has
60  // propagated through the CDC synchronizer and been sampled on the lower
61  // frequency (200kHz) AON clock; allow 3 clock cycles.
62  busy_spin_micros(15u);
63  TRY(dif_usbdev_set_wake_enable(usbdev.dev, enable));
64  // The AON Wake module operates on a 200kHz clock, so the clock period is
65  // 5us; we have CDC between USBDEV and AON Wake, but it responds within a
66  // couple of its clock cycles, so this is plenty.
67  ibex_timeout_t timeout = ibex_timeout_init(20);
68  do {
70  TRY(dif_usbdev_get_wake_status(usbdev.dev, &status));
71  // In the requested state yet?
72  if (status.active == dif_toggle_to_bool(enable)) {
73  return OK_STATUS();
74  }
75  } while (!ibex_timeout_check(&timeout));
76 
77  return DEADLINE_EXCEEDED();
78 }
79 
80 static status_t wait_until_configured(uint32_t timeout_micros) {
81  ibex_timeout_t timeout = ibex_timeout_init(timeout_micros);
82  while (!ibex_timeout_check(&timeout)) {
83  CHECK_STATUS_OK(usb_testutils_poll(&usbdev));
84  if (usbdev_control.device_state == kUsbTestutilsDeviceConfigured)
85  return OK_STATUS();
86  }
87  return DEADLINE_EXCEEDED();
88 }
89 
90 static status_t wait_until_suspended(uint32_t timeout_micros) {
91  ibex_timeout_t timeout = ibex_timeout_init(timeout_micros);
92  while (usbdev_control.device_state == kUsbTestutilsDeviceConfigured &&
93  !ibex_timeout_check(&timeout)) {
94  CHECK_STATUS_OK(usb_testutils_poll(&usbdev));
95  dif_usbdev_link_state_t link_state;
96  CHECK_DIF_OK(dif_usbdev_status_get_link_state(usbdev.dev, &link_state));
97  if (link_state == kDifUsbdevLinkStateSuspended) {
98  return OK_STATUS();
99  }
100  }
101  return DEADLINE_EXCEEDED();
102 }
103 
104 static status_t wait_until_aon_bus_reset(uint32_t timeout_micros) {
106  ibex_timeout_t timeout = ibex_timeout_init(timeout_micros);
107  while (!ibex_timeout_check(&timeout)) {
108  CHECK_DIF_OK(dif_usbdev_get_wake_status(usbdev.dev, &status));
109  CHECK(status.active, "AON wake is not active?!");
110  CHECK(!status.disconnected,
111  "device was disconnected while waiting for reset");
112  if (status.bus_reset)
113  return OK_STATUS();
114  }
115  return DEADLINE_EXCEEDED();
116 }
117 
118 bool test_main(void) {
119  uint32_t timeout_micros = 30 * 1000 * 1000u;
121 
122  init_peripherals();
123 
124  // Proceed only when the device has been configured.
125  LOG_INFO("wait for host to configure device...");
126  CHECK_STATUS_OK(wait_until_configured(timeout_micros));
127 
128  // Wait for the host to suspend the device.
129  LOG_INFO("configured, waiting for suspend");
130  CHECK_STATUS_OK(wait_until_suspended(timeout_micros));
131 
132  // Hand over control of the USB to the AON Wake module
133  CHECK_STATUS_OK(aon_wait(kDifToggleEnabled));
134 
135  // Wait until AON reports a bus reset.
136  LOG_INFO("suspended, waiting for reset");
137  CHECK_STATUS_OK(wait_until_aon_bus_reset(timeout_micros));
138 
139  LOG_INFO("reset, take control back from aon");
140  // Reclaim control of the USB by disabling the AON Wake module.
141  CHECK_STATUS_OK(aon_wait(kDifToggleDisabled));
142 
143  CHECK_STATUS_OK(usb_testutils_fin(&usbdev));
144 
145  return true;
146 }