Software APIs
pwrmgr_usb_clk_disabled_when_active_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 // Tests the pwrmgr setting to disable the USB clock in active mode. The check
6 // is to issue a USB CSR access when the clock is disabled, expecting the USB to
7 // hung, and causing a watchdog reset.
8 
15 #include "sw/device/lib/testing/aon_timer_testutils.h"
16 #include "sw/device/lib/testing/pwrmgr_testutils.h"
17 #include "sw/device/lib/testing/rstmgr_testutils.h"
18 #include "sw/device/lib/testing/test_framework/check.h"
20 
21 #include "usbdev_regs.h"
22 
23 static_assert(kDtPwrmgrCount == 1, "this test expects exactly one pwrmgr");
24 static const dt_pwrmgr_t kPwrmgrDt = 0;
25 static_assert(kDtRstmgrCount == 1, "this test expects exactly one rstmgr");
26 static const dt_rstmgr_t kRstmgrDt = 0;
27 static_assert(kDtAonTimerCount >= 1,
28  "this test expects at least one aon_timer");
29 static const dt_aon_timer_t kAonTimerDt = 0;
30 static const dt_usbdev_t kUsbdevDt = 0;
31 static_assert(kDtUsbdevCount >= 1, "this test expects at least one usbdev");
32 
33 OTTF_DEFINE_TEST_CONFIG();
34 
35 static dif_aon_timer_t aon_timer;
36 static dif_usbdev_t usbdev;
37 
38 static const uint32_t kExpectedHungOffset = USBDEV_INTR_ENABLE_REG_OFFSET;
39 
40 static void usbdev_csr_access(void) {
41  CHECK_DIF_OK(dif_usbdev_irq_set_enabled(&usbdev, kDifUsbdevIrqPowered,
43  dif_toggle_t state;
44  CHECK_DIF_OK(
45  dif_usbdev_irq_get_enabled(&usbdev, kDifUsbdevIrqPowered, &state));
46  CHECK(state == kDifToggleEnabled);
47 }
48 
49 bool test_main(void) {
50  dif_pwrmgr_t pwrmgr;
51  dif_rstmgr_t rstmgr;
52 
53  CHECK_DIF_OK(dif_rstmgr_init_from_dt(kRstmgrDt, &rstmgr));
54  CHECK_DIF_OK(dif_pwrmgr_init_from_dt(kPwrmgrDt, &pwrmgr));
55  CHECK_DIF_OK(dif_aon_timer_init_from_dt(kAonTimerDt, &aon_timer));
56  CHECK_DIF_OK(dif_usbdev_init_from_dt(kUsbdevDt, &usbdev));
57 
58  // Enable cpu dump capture.
59  CHECK_DIF_OK(dif_rstmgr_cpu_info_set_enabled(&rstmgr, kDifToggleEnabled));
60 
61  if (UNWRAP(rstmgr_testutils_is_reset_info(&rstmgr, kDifRstmgrResetInfoPor))) {
62  CHECK_STATUS_OK(rstmgr_testutils_pre_reset(&rstmgr));
63 
64  // Make sure the USB CSR access is okay before turning off the USB clock.
65  usbdev_csr_access();
66 
67  // Bite after enough time has elapsed past the hung csr access.
68  uint32_t bite_us = (kDeviceType == kDeviceSimDV) ? 400 : 800;
69  uint32_t bite_cycles = 0;
70  CHECK_STATUS_OK(
71  aon_timer_testutils_get_aon_cycles_32_from_us(bite_us, &bite_cycles));
72  LOG_INFO("Setting bite reset for %u us (%u cycles)", bite_us, bite_cycles);
73 
74  // Set bite timer.
75  CHECK_STATUS_OK(aon_timer_testutils_watchdog_config(&aon_timer, UINT32_MAX,
76  bite_cycles, false));
77 
78  // Enable watchdog bite reset.
79  dif_pwrmgr_request_sources_t reset_sources;
80  CHECK_DIF_OK(dif_pwrmgr_find_request_source(
81  &pwrmgr, kDifPwrmgrReqTypeReset, dt_aon_timer_instance_id(kAonTimerDt),
82  kDtAonTimerResetReqAonTimer, &reset_sources));
83  CHECK_DIF_OK(dif_pwrmgr_set_request_sources(
84  &pwrmgr, kDifPwrmgrReqTypeReset, reset_sources, kDifToggleDisabled));
85 
86  // Disable the USB in active mode, and wait some microseconds for the
87  // register update to propagate to the AST.
88  CHECK_DIF_OK(dif_pwrmgr_set_domain_config(&pwrmgr, 0, kDifToggleEnabled));
89  busy_spin_micros(50);
90 
91  // This should cause the CPU to hung.
92  usbdev_csr_access();
93 
94  // This should never be reached.
95  LOG_ERROR("This is unreachable since a reset should have been triggered");
96  return false;
97  } else if (UNWRAP(rstmgr_testutils_is_reset_info(
98  &rstmgr, kDifRstmgrResetInfoWatchdog))) {
99  LOG_INFO("Got an expected watchdog reset when accessing USB");
100 
101  size_t actual_size;
102  CHECK_DIF_OK(dif_rstmgr_cpu_info_get_size(&rstmgr, &actual_size));
103  // Verify the cpu crash dump.
105  size_t size_read;
106  CHECK_DIF_OK(dif_rstmgr_cpu_info_dump_read(
107  &rstmgr, cpu_dump, DIF_RSTMGR_CPU_INFO_MAX_SIZE, &size_read));
108  CHECK(size_read <= DIF_RSTMGR_CPU_INFO_MAX_SIZE);
109  CHECK(size_read == actual_size);
110  LOG_INFO("EXC_ADDR = 0x%x", cpu_dump[0]);
111  LOG_INFO("EXC_PC = 0x%x", cpu_dump[1]);
112  LOG_INFO("LAST_DATA ADDR = 0x%x", cpu_dump[2]);
113  LOG_INFO("NEXT_PC = 0x%x", cpu_dump[3]);
114  LOG_INFO("CURRENT_PC = 0x%x", cpu_dump[4]);
115  LOG_INFO("PREV_EXC_ADDR = 0x%x", cpu_dump[5]);
116  LOG_INFO("PREV_EXC_PC = 0x%x", cpu_dump[6]);
117  LOG_INFO("PREV_VALID = 0x%x", cpu_dump[7]);
118  // The cpu dump has the address that was last accessed at index 2.
119  uint32_t expected_addr =
120  dt_usbdev_primary_reg_block(kUsbdevDt) + kExpectedHungOffset;
121  CHECK(cpu_dump[2] == expected_addr, "Unexpected hung address");
122  return true;
123  } else {
125  reset_info = rstmgr_testutils_reason_get();
126  LOG_ERROR("Unexpected reset_info 0x%x", reset_info);
127  }
128  return false;
129 }