Software APIs
ast_usb_clk_calib.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 
10 #include "sw/device/lib/testing/clkmgr_testutils.h"
11 #include "sw/device/lib/testing/test_framework/FreeRTOSConfig.h"
12 #include "sw/device/lib/testing/test_framework/check.h"
14 
15 #include "ast_regs.h" // Generated.
17 
18 OTTF_DEFINE_TEST_CONFIG();
19 
20 static dif_clkmgr_t clkmgr;
21 static dif_usbdev_t usbdev;
22 static dif_pinmux_t pinmux;
23 
24 static uint32_t device_usb_count;
25 static uint32_t aon_clk_period_us;
26 
27 // Copied from sw/device/lib/testing/clkgmr_testutils.c
28 static uint32_t cast_safely(uint64_t val) {
29  CHECK(val <= UINT32_MAX);
30  return (uint32_t)val;
31 }
32 
33 static inline uint32_t get_count_variability(uint32_t cycles,
34  uint32_t variability_percentage) {
35  return ((cycles * variability_percentage) + 99) / 100 + 1;
36 }
37 
38 typedef struct expected_count_info {
39  uint32_t count;
40  uint32_t variability;
42 
43 static expected_count_info_t usb_count_info;
44 static uint32_t kVariabilityPercentage = 5;
45 
46 // This variable can be overwritten from the TB side side to speed up
47 // simulation. By default, it is set to 1ms, which matches the nominal sof
48 // packet interval. During simulation however, waiting for a few ms can be very
49 // costly in real time, so we give the testbench the option to override this
50 // value and speed things up.
51 static volatile const uint32_t kSoFPeriodUs = 1000;
52 
53 static void enable_usb_meas_get_code(dif_clkmgr_t *clkmgr,
55  CHECK_STATUS_OK(clkmgr_testutils_enable_clock_count(
57  usb_count_info.count - usb_count_info.variability,
58  usb_count_info.count + usb_count_info.variability));
59 
60  // Wait for measurements to go through a few cycles.
61  busy_spin_micros(5 * aon_clk_period_us);
62 
63  CHECK_DIF_OK(dif_clkmgr_recov_err_code_get_codes(clkmgr, codes));
64 };
65 
66 bool test_main(void) {
67  CHECK_DIF_OK(dif_clkmgr_init(
69 
70  CHECK_DIF_OK(dif_usbdev_init(
72 
73  CHECK_DIF_OK(dif_pinmux_init(
75 
76  aon_clk_period_us =
77  cast_safely(udiv64_slow(1000 * 1000, kClockFreqAonHz, NULL));
78  LOG_INFO("Each aon clock is %d us", aon_clk_period_us);
79 
80  device_usb_count =
81  cast_safely(udiv64_slow(kClockFreqUsbHz, kClockFreqAonHz, NULL));
82 
83  usb_count_info.count = device_usb_count - 1;
84  usb_count_info.variability =
85  get_count_variability(device_usb_count, kVariabilityPercentage);
86 
87  // First, connect usb.
88  LOG_INFO("Enable usb");
89  CHECK_DIF_OK(dif_pinmux_input_select(
92 
93  CHECK_DIF_OK(dif_usbdev_interface_enable(&usbdev, kDifToggleEnabled));
94 
96 
97  CHECK_DIF_OK(
99  CHECK_DIF_OK(dif_clkmgr_recov_err_code_clear_codes(&clkmgr, codes));
100  busy_spin_micros(5 * aon_clk_period_us);
101 
102  // Third, wait for usbdev sof calibration to execute
103  LOG_INFO("Wait for sof to calibrate clocks");
104  // Wait for a few sofs.
105  busy_spin_micros((AST_PARAM_NUM_USB_BEACON_PULSES + 2) * kSoFPeriodUs);
106 
107  // Last, measure clocks after usb calibration. They should be very accurate.
108  // re-enable measurements.
109  enable_usb_meas_get_code(&clkmgr, &codes);
110 
111  if (codes) {
112  LOG_FATAL("Error code is non-zero 0x%h", codes);
113  }
114 
115  LOG_INFO("sof complete");
116  return true;
117 }