Software APIs
clkmgr_external_clk_src_for_sw_impl.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 runs a test with external clock enabled via software for either fast
6 // or slow speed. It checks the expected frequencies via the clock count
7 // measurement feature. After the measurements are made, the external clock is
8 // disabled and the clock counts are measured to confirm the frequencies are
9 // back to what is expected when the external clock is not enabled.
10 
17 #include "sw/device/lib/testing/aon_timer_testutils.h"
18 #include "sw/device/lib/testing/clkmgr_testutils.h"
19 #include "sw/device/lib/testing/test_framework/check.h"
20 
22 
23 // Switching to external clocks causes the clocks to be unstable for some time.
24 // This is used to delay further action when the switch happens.
25 static const int kSettleDelayMicros = 200;
26 static const int kMeasurementsPerRound = 100;
27 
28 // For passing into `IBEX_SPIN_FOR`.
29 static bool did_extclk_settle(const dif_clkmgr_t *clkmgr) {
30  bool status;
31  CHECK_DIF_OK(dif_clkmgr_external_clock_is_settled(clkmgr, &status));
32  return status;
33 }
34 
35 void execute_clkmgr_external_clk_src_for_sw_test(bool fast_ext_clk) {
36  dif_clkmgr_t clkmgr;
38 
39  uint32_t delay_micros = 0;
40  CHECK_STATUS_OK(aon_timer_testutils_get_us_from_aon_cycles(
41  kMeasurementsPerRound, &delay_micros));
42 
43  CHECK_DIF_OK(dif_clkmgr_init(
45 
46  CHECK_DIF_OK(dif_clkmgr_recov_err_code_clear_codes(&clkmgr, UINT32_MAX));
47  CHECK_DIF_OK(dif_clkmgr_recov_err_code_get_codes(&clkmgr, &err_codes));
48  CHECK(err_codes == 0, "Unexpected non-zero clkmgr recoverable error code");
49 
50  // Configure external clock:
51  // - at low speed (48 MHz) both main and io clocks count are the nominal
52  // IoDiv2's.
53  // - at high speed (96 MHz) the main clock count is the nominal Io's.
54  LOG_INFO("Selecting external clock and %s speed clocks",
55  (fast_ext_clk ? "fast" : "slow"));
56  CHECK_DIF_OK(
58  /*is_low_speed=*/!fast_ext_clk));
59 
60  // Wait for the external clock to become active.
61  IBEX_SPIN_FOR(did_extclk_settle(&clkmgr), kSettleDelayMicros);
62  LOG_INFO("External clock enabled");
63 
64  CHECK_STATUS_OK(clkmgr_testutils_enable_clock_counts_with_expected_thresholds(
65  &clkmgr, /*jitter_enabled=*/false, /*external_clk=*/true,
66  /*low_speed=*/!fast_ext_clk));
67  busy_spin_micros(delay_micros);
68 
69  CHECK_STATUS_OK(clkmgr_testutils_check_measurement_counts(&clkmgr));
70  CHECK_STATUS_OK(clkmgr_testutils_disable_clock_counts(&clkmgr));
71 
72  // Disable the external clock and check the frequencies are as expected
73  // when driven by the AST oscillators.
74  LOG_INFO("Disabling external clock");
75  CHECK_DIF_OK(dif_clkmgr_external_clock_set_disabled(&clkmgr));
76 
77  // Wait for the external clock to become inactive.
78  IBEX_SPIN_FOR(!did_extclk_settle(&clkmgr), kSettleDelayMicros);
79  LOG_INFO("External clock disabled");
80 
81  CHECK_STATUS_OK(clkmgr_testutils_enable_clock_counts_with_expected_thresholds(
82  &clkmgr, /*jitter_enabled=*/false, /*external_clk=*/false,
83  /*low_speed=*/!fast_ext_clk));
84  busy_spin_micros(delay_micros);
85  CHECK_STATUS_OK(clkmgr_testutils_check_measurement_counts(&clkmgr));
86  CHECK_STATUS_OK(clkmgr_testutils_disable_clock_counts(&clkmgr));
87 }