Software APIs
clkmgr_off_peri_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 
12 #include "sw/device/lib/dif/dif_rv_core_ibex.h"
17 #include "sw/device/lib/testing/aon_timer_testutils.h"
18 #include "sw/device/lib/testing/ret_sram_testutils.h"
19 #include "sw/device/lib/testing/rstmgr_testutils.h"
20 #include "sw/device/lib/testing/test_framework/check.h"
22 
24 #include "spi_host_regs.h"
25 #include "uart_regs.h"
26 #include "usbdev_regs.h"
27 
28 static const dt_pwrmgr_t kPwrmgrDt = 0;
29 static_assert(kDtPwrmgrCount == 1, "this test expects a pwrmgr");
30 
31 /**
32  * The peripherals used to test when the peri clocks are disabled are
33  * bit 0: clk_io_div4_peri: uart0
34  * bit 1: clk_io_div2_peri: spi_host1
35  * bit 2: clk_io_peri: spi_host0
36  * bit 3: clk_usb_peri: usbdev
37  */
38 
39 OTTF_DEFINE_TEST_CONFIG();
40 
41 typedef struct peri_context {
42  const char *peripheral_name; // The name of the peripheral tested.
43  void (*csr_access)(void); // The function causing a timeout.
44  uint32_t address; // The address causing a timeout.
46 
47 /**
48  * The maximum offset past the entry point of the function that causes
49  * the cpu to hang.
50  */
51 enum { kPcSpread = 8 * 4 };
52 
53 static dif_aon_timer_t aon_timer;
54 static dif_spi_host_t spi_host0;
55 static dif_spi_host_t spi_host1;
56 static dif_usbdev_t usbdev;
57 static dif_uart_t uart0;
58 
59 OT_NOINLINE static void uart0_csr_access(void) {
60  dif_uart_irq_state_snapshot_t snapshot;
61  CHECK_DIF_OK(dif_uart_irq_get_state(&uart0, &snapshot));
62 }
63 
64 OT_NOINLINE static void spi_host0_csr_access(void) {
65  dif_spi_host_irq_state_snapshot_t snapshot;
66  CHECK_DIF_OK(dif_spi_host_irq_get_state(&spi_host0, &snapshot));
67 }
68 
69 OT_NOINLINE static void spi_host1_csr_access(void) {
70  CHECK_DIF_OK(dif_spi_host_output_set_enabled(&spi_host1, true));
71 }
72 
73 OT_NOINLINE static void usbdev_csr_access(void) {
74  dif_usbdev_irq_state_snapshot_t snapshot;
75  CHECK_DIF_OK(dif_usbdev_irq_get_state(&usbdev, &snapshot));
76 }
77 
78 peri_context_t peri_context[kTopEarlgreyGateableClocksLast + 1] = {
79  {"uart0", uart0_csr_access,
80  TOP_EARLGREY_UART0_BASE_ADDR + UART_INTR_STATE_REG_OFFSET},
81  {"spi_host1", spi_host1_csr_access,
82  TOP_EARLGREY_SPI_HOST1_BASE_ADDR + SPI_HOST_CONTROL_REG_OFFSET},
83  {"spi_host0", spi_host0_csr_access,
84  TOP_EARLGREY_SPI_HOST0_BASE_ADDR + SPI_HOST_INTR_STATE_REG_OFFSET},
85  {"usbdev", usbdev_csr_access,
86  TOP_EARLGREY_USBDEV_BASE_ADDR + USBDEV_INTR_STATE_REG_OFFSET}};
87 
88 /**
89  * Test that disabling a 'gateable' unit's clock causes the unit to become
90  * unresponsive to CSR accesses. Configure a watchdog reset, and if it triggers
91  * the test is successful.
92  */
93 static void test_gateable_clocks_off(const dif_clkmgr_t *clkmgr,
94  const dif_pwrmgr_t *pwrmgr,
96  // Make sure the clock for the unit is on.
97  CHECK_DIF_OK(
99  // Enable watchdog bite reset.
101  kDifPwrmgrResetRequestSourceTwo,
103  LOG_INFO("Testing peripheral clock %d, with unit %s", clock,
104  peri_context[clock].peripheral_name);
105 
106  // Bite after enough time has elapsed past the hung csr access.
107  uint32_t bite_us = (kDeviceType == kDeviceSimDV) ? 400 : 800;
108  uint32_t bite_cycles = 0;
109  CHECK_STATUS_OK(
110  aon_timer_testutils_get_aon_cycles_32_from_us(bite_us, &bite_cycles));
111  LOG_INFO("Setting bite reset for %u us (%u cycles)", bite_us, bite_cycles);
112 
113  // Make sure the CSR is accessible before turning the clock off.
114  (*peri_context[clock].csr_access)();
115  LOG_INFO("CSR access was okay before disabling the clock");
116 
117  // Set bite timer.
118  CHECK_STATUS_OK(aon_timer_testutils_watchdog_config(&aon_timer, UINT32_MAX,
119  bite_cycles, false));
120  // Disable the peripheral's clock.
121  CHECK_DIF_OK(
123  // Wait for the clock to really turn off.
124  busy_spin_micros(100);
125  // And issue the CSR access that will freeze and cause a reset.
126  (*peri_context[clock].csr_access)();
127 }
128 
129 bool test_main(void) {
130  dif_clkmgr_t clkmgr;
131  dif_pwrmgr_t pwrmgr;
132  dif_rstmgr_t rstmgr;
133 
134  CHECK_DIF_OK(dif_rstmgr_init(
136 
137  CHECK_DIF_OK(dif_clkmgr_init(
139 
140  CHECK_DIF_OK(dif_pwrmgr_init_from_dt(kPwrmgrDt, &pwrmgr));
141 
142  // Initialize aon timer.
143  CHECK_DIF_OK(dif_aon_timer_init(
145 
146  // Initialize peripherals.
147  CHECK_DIF_OK(dif_uart_init(
149  CHECK_DIF_OK(dif_spi_host_init(
151  CHECK_DIF_OK(dif_spi_host_init(
153  CHECK_DIF_OK(dif_usbdev_init(
155 
156  // Initialize the retention sram utils.
157  ret_sram_testutils_init();
158 
159  // Enable cpu dump capture.
160  CHECK_DIF_OK(dif_rstmgr_cpu_info_set_enabled(&rstmgr, kDifToggleEnabled));
161  if (UNWRAP(rstmgr_testutils_is_reset_info(&rstmgr, kDifRstmgrResetInfoPor))) {
162  CHECK_STATUS_OK(rstmgr_testutils_pre_reset(&rstmgr));
163 
164  // Starting clock.
166  uint32_t prev_value = 0;
167  uint32_t value = 0;
168  CHECK_STATUS_OK(ret_sram_testutils_counter_clear(0));
169  for (int i = 0; i < 20; ++i) {
170  CHECK_STATUS_OK(ret_sram_testutils_counter_increment(0));
171  CHECK_STATUS_OK(ret_sram_testutils_counter_get(0, &value));
172  CHECK(value == prev_value + 1);
173  prev_value = value;
174  }
175  CHECK_STATUS_OK(ret_sram_testutils_counter_clear(0));
176  CHECK_STATUS_OK(ret_sram_testutils_counter_get(0, &value));
177 
178  test_gateable_clocks_off(&clkmgr, &pwrmgr, clock);
179 
180  // This should never be reached.
181  LOG_ERROR("This is unreachable since a reset should have been triggered");
182  return false;
183  } else if (UNWRAP(rstmgr_testutils_is_reset_info(
184  &rstmgr, kDifRstmgrResetInfoWatchdog))) {
185  dif_clkmgr_gateable_clock_t clock = {0};
186  CHECK_STATUS_OK(ret_sram_testutils_counter_get(0, &clock));
187  LOG_INFO("Got an expected watchdog reset when reading for clock %d", clock);
188 
189  size_t actual_size;
190  CHECK_DIF_OK(dif_rstmgr_cpu_info_get_size(&rstmgr, &actual_size));
192  // The sizes for dif_rstmgr_cpu_info_dump_read are measured in
193  // units of dif_rstmgr_cpu_info_dump_segment_t.
194  size_t size_read;
195  CHECK_DIF_OK(dif_rstmgr_cpu_info_dump_read(
196  &rstmgr, (dif_rstmgr_cpu_info_dump_segment_t *)&crash_dump,
197  sizeof(crash_dump) / sizeof(dif_rstmgr_cpu_info_dump_segment_t),
198  &size_read));
199  CHECK(size_read == actual_size);
200  uint32_t expected_hung_address = peri_context[clock].address;
201  CHECK(crash_dump.fault_state.mdaa == expected_hung_address,
202  "Unexpected hung address for clock %d, via peripheral %s", clock,
203  peri_context[clock].peripheral_name);
204  // Check the fault PC is close enough to the address of the function
205  // that causes the hung access.
206  uint32_t crash_function = (uint32_t)peri_context[clock].csr_access;
207  CHECK(crash_dump.fault_state.mcpc >= crash_function &&
208  crash_dump.fault_state.mcpc <= crash_function + kPcSpread,
209  "The crash PC 0x%x is too far from the expected 0x%x",
210  crash_dump.fault_state.mcpc, crash_function);
211  // Mark this clock as tested.
212  LOG_INFO("Expectations are okay for clock %d, with peripheral %s", clock,
213  peri_context[clock].peripheral_name);
214  CHECK_STATUS_OK(ret_sram_testutils_counter_increment(0));
215 
216  if (clock < kTopEarlgreyGateableClocksLast) {
217  CHECK_STATUS_OK(ret_sram_testutils_counter_get(0, &clock));
218  LOG_INFO("Next clock to test %d", clock);
219 
220  CHECK_STATUS_OK(rstmgr_testutils_pre_reset(&rstmgr));
221 
222  test_gateable_clocks_off(&clkmgr, &pwrmgr, clock);
223 
224  // This should never be reached.
225  LOG_ERROR("This is unreachable since a reset should have been triggered");
226  return false;
227  } else {
228  return true;
229  }
230  } else {
232  reset_info = rstmgr_testutils_reason_get();
233  LOG_ERROR("Unexpected reset_info 0x%x", reset_info);
234  }
235  return false;
236 }