| // Copyright lowRISC contributors. | 
 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
 | // SPDX-License-Identifier: Apache-2.0 | 
 |  | 
 | #include "sw/device/lib/base/memory.h" | 
 | #include "sw/device/lib/dif/dif_base.h" | 
 | #include "sw/device/lib/dif/dif_clkmgr.h" | 
 | #include "sw/device/lib/testing/test_framework/check.h" | 
 | #include "sw/device/lib/testing/test_framework/ottf_main.h" | 
 |  | 
 | #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" | 
 |  | 
 | OTTF_DEFINE_TEST_CONFIG(); | 
 |  | 
 | /** | 
 |  * Test that all 'gateable' clocks, directly controlled by software, | 
 |  * can be enabled and disabled. | 
 |  */ | 
 | static void test_gateable_clocks(const dif_clkmgr_t *clkmgr) { | 
 |   for (dif_clkmgr_gateable_clock_t clock = 0; | 
 |        clock <= kTopEarlgreyGateableClocksLast; ++clock) { | 
 |     // Get the initial state of the clock. The clock might be enabled or | 
 |     // disabled depending on reset behavior - either is fine for the purposes of | 
 |     // this test. | 
 |     dif_toggle_t state; | 
 |     CHECK_DIF_OK(dif_clkmgr_gateable_clock_get_enabled(clkmgr, clock, &state)); | 
 |  | 
 |     // Toggle the enable twice so that it ends up in its original state. | 
 |     for (int j = 0; j < 2; ++j) { | 
 |       dif_toggle_t expected_state = | 
 |           state == kDifToggleEnabled ? kDifToggleDisabled : kDifToggleEnabled; | 
 |       dif_toggle_t actual_state = state; | 
 |       CHECK_DIF_OK( | 
 |           dif_clkmgr_gateable_clock_set_enabled(clkmgr, clock, expected_state)); | 
 |       CHECK_DIF_OK( | 
 |           dif_clkmgr_gateable_clock_get_enabled(clkmgr, clock, &actual_state)); | 
 |       CHECK(actual_state == expected_state); | 
 |  | 
 |       state = actual_state; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | /** | 
 |  * Test that all 'hintable' clocks, indirectly controlled by software, | 
 |  * can have their hint toggled and status checked. | 
 |  */ | 
 | void test_hintable_clocks(const dif_clkmgr_t *clkmgr) { | 
 |   for (dif_clkmgr_hintable_clock_t clock = 0; | 
 |        clock <= kTopEarlgreyHintableClocksLast; ++clock) { | 
 |     // Get the initial state of the hint for the clock The clock hint might be | 
 |     // enabled or disabled depending on reset behavior - either is fine for the | 
 |     // purposes of this test. | 
 |     dif_toggle_t state; | 
 |     CHECK_DIF_OK(dif_clkmgr_hintable_clock_get_hint(clkmgr, clock, &state)); | 
 |  | 
 |     // Toggle the hint twice so that it ends up in its original state. | 
 |     for (int j = 0; j < 2; ++j) { | 
 |       dif_toggle_t expected_state = | 
 |           state == kDifToggleEnabled ? kDifToggleDisabled : kDifToggleEnabled; | 
 |       dif_toggle_t actual_state = state; | 
 |       CHECK_DIF_OK( | 
 |           dif_clkmgr_hintable_clock_set_hint(clkmgr, clock, expected_state)); | 
 |       CHECK_DIF_OK( | 
 |           dif_clkmgr_hintable_clock_get_hint(clkmgr, clock, &actual_state)); | 
 |       CHECK(actual_state == expected_state); | 
 |  | 
 |       // If the clock hint is enabled then the clock should always be enabled. | 
 |       if (actual_state == kDifToggleEnabled) { | 
 |         dif_toggle_t state = kDifToggleDisabled; | 
 |         CHECK_DIF_OK( | 
 |             dif_clkmgr_hintable_clock_get_enabled(clkmgr, clock, &state)); | 
 |         CHECK(state == kDifToggleEnabled, | 
 |               "clock %u hint is enabled but status is disabled", clock); | 
 |       } | 
 |  | 
 |       state = actual_state; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | bool test_main(void) { | 
 |   dif_clkmgr_t clkmgr; | 
 |   CHECK_DIF_OK(dif_clkmgr_init( | 
 |       mmio_region_from_addr(TOP_EARLGREY_CLKMGR_AON_BASE_ADDR), &clkmgr)); | 
 |   test_gateable_clocks(&clkmgr); | 
 |   test_hintable_clocks(&clkmgr); | 
 |  | 
 |   return true; | 
 | } |