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.
100  dif_pwrmgr_request_sources_t reset_sources;
101  CHECK_DIF_OK(dif_pwrmgr_find_request_source(
102  pwrmgr, kDifPwrmgrReqTypeReset, dt_aon_timer_instance_id(kDtAonTimerAon),
103  kDtAonTimerResetReqAonTimer, &reset_sources));
104  CHECK_DIF_OK(dif_pwrmgr_set_request_sources(
105  pwrmgr, kDifPwrmgrReqTypeReset, reset_sources, kDifToggleEnabled));
106  LOG_INFO("Testing peripheral clock %d, with unit %s", clock,
107  peri_context[clock].peripheral_name);
108 
109  // Bite after enough time has elapsed past the hung csr access.
110  uint32_t bite_us = (kDeviceType == kDeviceSimDV) ? 400 : 800;
111  uint32_t bite_cycles = 0;
112  CHECK_STATUS_OK(
113  aon_timer_testutils_get_aon_cycles_32_from_us(bite_us, &bite_cycles));
114  LOG_INFO("Setting bite reset for %u us (%u cycles)", bite_us, bite_cycles);
115 
116  // Make sure the CSR is accessible before turning the clock off.
117  (*peri_context[clock].csr_access)();
118  LOG_INFO("CSR access was okay before disabling the clock");
119 
120  // Set bite timer.
121  CHECK_STATUS_OK(aon_timer_testutils_watchdog_config(&aon_timer, UINT32_MAX,
122  bite_cycles, false));
123  // Disable the peripheral's clock.
124  CHECK_DIF_OK(
126  // Wait for the clock to really turn off.
127  busy_spin_micros(100);
128  // And issue the CSR access that will freeze and cause a reset.
129  (*peri_context[clock].csr_access)();
130 }
131 
132 bool test_main(void) {
133  dif_clkmgr_t clkmgr;
134  dif_pwrmgr_t pwrmgr;
135  dif_rstmgr_t rstmgr;
136 
137  CHECK_DIF_OK(dif_rstmgr_init(
139 
140  CHECK_DIF_OK(dif_clkmgr_init(
142 
143  CHECK_DIF_OK(dif_pwrmgr_init_from_dt(kPwrmgrDt, &pwrmgr));
144 
145  // Initialize aon timer.
146  CHECK_DIF_OK(dif_aon_timer_init(
148 
149  // Initialize peripherals.
150  CHECK_DIF_OK(dif_uart_init(
152  CHECK_DIF_OK(dif_spi_host_init(
154  CHECK_DIF_OK(dif_spi_host_init(
156  CHECK_DIF_OK(dif_usbdev_init(
158 
159  // Initialize the retention sram utils.
160  ret_sram_testutils_init();
161 
162  // Enable cpu dump capture.
163  CHECK_DIF_OK(dif_rstmgr_cpu_info_set_enabled(&rstmgr, kDifToggleEnabled));
164  if (UNWRAP(rstmgr_testutils_is_reset_info(&rstmgr, kDifRstmgrResetInfoPor))) {
165  CHECK_STATUS_OK(rstmgr_testutils_pre_reset(&rstmgr));
166 
167  // Starting clock.
169  uint32_t prev_value = 0;
170  uint32_t value = 0;
171  CHECK_STATUS_OK(ret_sram_testutils_counter_clear(0));
172  for (int i = 0; i < 20; ++i) {
173  CHECK_STATUS_OK(ret_sram_testutils_counter_increment(0));
174  CHECK_STATUS_OK(ret_sram_testutils_counter_get(0, &value));
175  CHECK(value == prev_value + 1);
176  prev_value = value;
177  }
178  CHECK_STATUS_OK(ret_sram_testutils_counter_clear(0));
179  CHECK_STATUS_OK(ret_sram_testutils_counter_get(0, &value));
180 
181  test_gateable_clocks_off(&clkmgr, &pwrmgr, clock);
182 
183  // This should never be reached.
184  LOG_ERROR("This is unreachable since a reset should have been triggered");
185  return false;
186  } else if (UNWRAP(rstmgr_testutils_is_reset_info(
187  &rstmgr, kDifRstmgrResetInfoWatchdog))) {
188  dif_clkmgr_gateable_clock_t clock = {0};
189  CHECK_STATUS_OK(ret_sram_testutils_counter_get(0, &clock));
190  LOG_INFO("Got an expected watchdog reset when reading for clock %d", clock);
191 
192  size_t actual_size;
193  CHECK_DIF_OK(dif_rstmgr_cpu_info_get_size(&rstmgr, &actual_size));
195  // The sizes for dif_rstmgr_cpu_info_dump_read are measured in
196  // units of dif_rstmgr_cpu_info_dump_segment_t.
197  size_t size_read;
198  CHECK_DIF_OK(dif_rstmgr_cpu_info_dump_read(
199  &rstmgr, (dif_rstmgr_cpu_info_dump_segment_t *)&crash_dump,
200  sizeof(crash_dump) / sizeof(dif_rstmgr_cpu_info_dump_segment_t),
201  &size_read));
202  CHECK(size_read == actual_size);
203  uint32_t expected_hung_address = peri_context[clock].address;
204  CHECK(crash_dump.fault_state.mdaa == expected_hung_address,
205  "Unexpected hung address for clock %d, via peripheral %s", clock,
206  peri_context[clock].peripheral_name);
207  // Check the fault PC is close enough to the address of the function
208  // that causes the hung access.
209  uint32_t crash_function = (uint32_t)peri_context[clock].csr_access;
210  CHECK(crash_dump.fault_state.mcpc >= crash_function &&
211  crash_dump.fault_state.mcpc <= crash_function + kPcSpread,
212  "The crash PC 0x%x is too far from the expected 0x%x",
213  crash_dump.fault_state.mcpc, crash_function);
214  // Mark this clock as tested.
215  LOG_INFO("Expectations are okay for clock %d, with peripheral %s", clock,
216  peri_context[clock].peripheral_name);
217  CHECK_STATUS_OK(ret_sram_testutils_counter_increment(0));
218 
219  if (clock < kTopEarlgreyGateableClocksLast) {
220  CHECK_STATUS_OK(ret_sram_testutils_counter_get(0, &clock));
221  LOG_INFO("Next clock to test %d", clock);
222 
223  CHECK_STATUS_OK(rstmgr_testutils_pre_reset(&rstmgr));
224 
225  test_gateable_clocks_off(&clkmgr, &pwrmgr, clock);
226 
227  // This should never be reached.
228  LOG_ERROR("This is unreachable since a reset should have been triggered");
229  return false;
230  } else {
231  return true;
232  }
233  } else {
235  reset_info = rstmgr_testutils_reason_get();
236  LOG_ERROR("Unexpected reset_info 0x%x", reset_info);
237  }
238  return false;
239 }