blob: 9d801f46363d8184aeb5224130fd92ebcc9a4d02 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// This runs a test with external clock enabled via software for either fast
// or slow speed. It checks the expected frequencies via the clock count
// measurement feature.
#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/runtime/hart.h"
#include "sw/device/lib/runtime/ibex.h"
#include "sw/device/lib/runtime/log.h"
#include "sw/device/lib/testing/aon_timer_testutils.h"
#include "sw/device/lib/testing/clkmgr_testutils.h"
#include "sw/device/lib/testing/test_framework/check.h"
#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
// Switching to external clocks causes the clocks to be unstable for some time.
// This is used to delay further action when the switch happens.
static const int kSettleDelayMicros = 200;
static const int kMeasurementsPerRound = 100;
// For passing into `IBEX_SPIN_FOR`.
static bool did_extclk_settle(const dif_clkmgr_t *clkmgr) {
bool status;
CHECK_DIF_OK(dif_clkmgr_external_clock_is_settled(clkmgr, &status));
return status;
}
void execute_clkmgr_external_clk_src_for_sw_test(bool fast_ext_clk) {
dif_clkmgr_t clkmgr;
dif_clkmgr_recov_err_codes_t err_codes;
uint32_t kMeasurementDelayMicros =
aon_timer_testutils_get_us_from_aon_cycles(kMeasurementsPerRound);
CHECK_DIF_OK(dif_clkmgr_init(
mmio_region_from_addr(TOP_EARLGREY_CLKMGR_AON_BASE_ADDR), &clkmgr));
CHECK_DIF_OK(dif_clkmgr_recov_err_code_clear_codes(&clkmgr, UINT32_MAX));
CHECK_DIF_OK(dif_clkmgr_recov_err_code_get_codes(&clkmgr, &err_codes));
LOG_INFO("Recoverable error codes 0x%x", err_codes);
LOG_INFO("Enabling clock count measurements");
clkmgr_testutils_enable_clock_counts_with_expected_thresholds(
&clkmgr, /*jitter_enabled=*/false, /*external_clk=*/false,
/*low_speed=*/false);
busy_spin_micros(kMeasurementDelayMicros);
CHECK(clkmgr_testutils_check_measurement_counts(&clkmgr));
clkmgr_testutils_disable_clock_counts(&clkmgr);
// Configure external clock:
// - at low speed (48 MHz) both main and io clocks count are the nominal
// IoDiv2's.
// - at high speed (96 MHz) the main clock count is the nominal Io's.
LOG_INFO("Selecting external clock and %s speed clocks",
(fast_ext_clk ? "fast" : "slow"));
CHECK_DIF_OK(
dif_clkmgr_external_clock_set_enabled(&clkmgr,
/*is_low_speed=*/!fast_ext_clk));
// Wait a few AON cycles for glitches from the transition to external
// clock to settle.
IBEX_SPIN_FOR(did_extclk_settle(&clkmgr), kSettleDelayMicros);
clkmgr_testutils_enable_clock_counts_with_expected_thresholds(
&clkmgr, /*jitter_enabled=*/false, /*external_clk=*/true,
/*low_speed=*/!fast_ext_clk);
busy_spin_micros(kMeasurementDelayMicros);
CHECK(clkmgr_testutils_check_measurement_counts(&clkmgr));
clkmgr_testutils_disable_clock_counts(&clkmgr);
}