Software APIs
pwrmgr_usbdev_smoketest.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 // This is a DV specific pwrmgr usbdev smoketest that fakes usb activity.
6 // Using the phy drive function of usbdev, we present the usbdev is in suspend
7 // and thus trigger low power entry.
8 // Once the system enters low power entry, the incoming USBP/USBN lines are
9 // immediately different from what the wake module expects and thus causes
10 // a wakeup.
11 // This test just smoke checks the pwrmgr's ability to enter / exit low power
12 // and the usbdev's aon wake function that has been de-coupled from the main
13 // usbdev.
14 
15 #include "dt/dt_pinmux.h"
21 #include "sw/device/lib/testing/pwrmgr_testutils.h"
22 #include "sw/device/lib/testing/test_framework/check.h"
24 
25 static dif_pwrmgr_t pwrmgr;
26 static dif_usbdev_t usbdev;
27 
28 static const dt_pwrmgr_t kPwrmgrDt = 0;
29 static_assert(kDtPwrmgrCount == 1, "this test expects a pwrmgr");
30 static const dt_pinmux_t kPinmuxDt = 0;
31 static_assert(kDtPinmuxCount == 1, "this test expects a pinmux");
32 static const dt_usbdev_t kUsbdevDt = 0;
33 static_assert(kDtUsbdevCount >= 1, "this test expects at least one usbdev");
34 
35 OTTF_DEFINE_TEST_CONFIG();
36 
37 static bool compare_wakeup_reasons(dif_pwrmgr_wakeup_reason_t lhs,
39  return lhs.types == rhs.types && lhs.request_sources == rhs.request_sources;
40 }
41 
42 bool test_main(void) {
43  CHECK_DIF_OK(dif_pwrmgr_init_from_dt(kPwrmgrDt, &pwrmgr));
44  CHECK_DIF_OK(dif_usbdev_init_from_dt(kUsbdevDt, &usbdev));
45 
46  dif_pwrmgr_request_sources_t wakeup_sources;
47  CHECK_DIF_OK(dif_pwrmgr_find_request_source(
48  &pwrmgr, kDifPwrmgrReqTypeWakeup, dt_pinmux_instance_id(kPinmuxDt),
49  kDtPinmuxWakeupUsbWkupReq, &wakeup_sources));
50 
51  // Assuming the chip hasn't slept yet, wakeup reason should be empty.
52  dif_pwrmgr_wakeup_reason_t wakeup_reason;
53  CHECK_DIF_OK(dif_pwrmgr_wakeup_reason_get(&pwrmgr, &wakeup_reason));
54 
55  const dif_pwrmgr_wakeup_reason_t exp_por_wakeup_reason = {
56  .types = 0,
57  .request_sources = 0,
58  };
59 
60  const dif_pwrmgr_wakeup_reason_t exp_test_wakeup_reason = {
62  .request_sources = wakeup_sources,
63  };
64 
65  bool low_power_exit = false;
66  if (compare_wakeup_reasons(wakeup_reason, exp_por_wakeup_reason)) {
67  LOG_INFO("Powered up for the first time, begin test");
68  } else if (compare_wakeup_reasons(wakeup_reason, exp_test_wakeup_reason)) {
69  low_power_exit = true;
70  LOG_INFO("USB wakeup detected");
71  } else {
72  LOG_ERROR("Unexpected wakeup reason (types: %02x, sources: %08x)",
73  wakeup_reason.types, wakeup_reason.request_sources);
74  return false;
75  }
76 
77  // Fake low power entry through usb
78  // Force wake detection module active
79  if (!low_power_exit) {
80  CHECK_DIF_OK(dif_usbdev_set_wake_enable(&usbdev, kDifToggleDisabled));
82  .dp_pullup_en = true,
83  .dn_pullup_en = false,
84  };
85  CHECK_DIF_OK(
87  CHECK_DIF_OK(dif_usbdev_set_wake_enable(&usbdev, kDifToggleEnabled));
88 
89  // give the hardware a chance to recognize the wakeup values are the same
90  busy_spin_micros(20); // 20us
91 
92  // Enable low power on the next WFI with default settings.
93  CHECK_STATUS_OK(pwrmgr_testutils_enable_low_power(
94  &pwrmgr, wakeup_sources, kDifPwrmgrDomainOptionUsbClockInActivePower));
95 
96  // Enter low power mode.
98  }
99 
100  return true;
101 }