blob: d8974c4eb73536474c995b7816fc42dc328037f5 [file] [log] [blame]
// 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_sensor_ctrl.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/pwrmgr_testutils.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();
/**
* AST CLK OUTPUTS TEST
*
* This test measure clock counts with clkmgr frequency measurements, performing
* 100 measurements per round. Measurement errors (fast or slow clocks) are
* recorded as recoverable error in clkmgr.
*
* After 100 measurements, test kicks in low-power mode, where
* 3 clocks are off and measurement should not report spurious errors.
*
* When the dut wakes up, another 100 measurements are done before the
* test finishes.
*
* Notice the test overrides the hardware behavior so it comes out with
* calibrated USB clock, otherwise the USB clock frequency will be incorrect.
* USB calibration should be a separate test, and may be vendor-specific.
*/
enum {
kWaitForCSRPollingUs = 1, // 1us
kMeasurementsPerRound = 100,
};
static dif_clkmgr_t clkmgr;
static dif_pwrmgr_t pwrmgr;
bool test_main(void) {
dif_sensor_ctrl_t sensor_ctrl;
dif_aon_timer_t aon_timer;
const 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_sensor_ctrl_init(
mmio_region_from_addr(TOP_EARLGREY_SENSOR_CTRL_BASE_ADDR), &sensor_ctrl));
CHECK_DIF_OK(dif_pwrmgr_init(
mmio_region_from_addr(TOP_EARLGREY_PWRMGR_AON_BASE_ADDR), &pwrmgr));
CHECK_DIF_OK(dif_aon_timer_init(
mmio_region_from_addr(TOP_EARLGREY_AON_TIMER_AON_BASE_ADDR), &aon_timer));
// TODO(#13611) Uncomment when fixed
/*
LOG_INFO("TEST: wait for ast init");
dif_toggle_t init_st = kDifToggleDisabled;
while (init_st == kDifToggleDisabled) {
CHECK_DIF_OK(
dif_sensor_ctrl_get_ast_init_done_status(&sensor_ctrl, &init_st));
busy_spin_micros(kWaitForCSRPollingUs);
}
LOG_INFO("TEST: done ast init");
*/
if (pwrmgr_testutils_is_wakeup_reason(&pwrmgr, 0)) {
// At POR.
LOG_INFO("Run clock measurements right after POR");
clkmgr_testutils_enable_clock_counts_with_expected_thresholds(
&clkmgr, /*jitter_enabled=*/false, /*external_clk=*/false,
/*low_speed=*/false);
busy_spin_micros(kMeasurementDelayMicros);
// check results
CHECK(clkmgr_testutils_check_measurement_counts(&clkmgr));
clkmgr_testutils_disable_clock_counts(&clkmgr);
// Set wakeup timer to 100 us to have enough down time, and also wait before
// entering deep sleep to have a chance to measure before sleeping.
// As a side-effect of deep sleep the clock measurements are disabled, but
// recoverable errors are not cleared.
//
// Set the counters so we should get an error unless they are cleared.
uint32_t wakeup_threshold = kDeviceType == kDeviceSimVerilator ? 1000 : 100;
aon_timer_testutils_wakeup_config(&aon_timer, wakeup_threshold);
LOG_INFO("Start clock measurements to cause an error for main clk.");
clkmgr_testutils_enable_clock_counts_with_expected_thresholds(
&clkmgr, /*jitter_enabled=*/false, /*external_clk=*/true,
/*low_speed=*/false);
// Disable writes to measure ctrl registers.
CHECK_DIF_OK(dif_clkmgr_measure_ctrl_disable(&clkmgr));
busy_spin_micros(kMeasurementDelayMicros);
pwrmgr_testutils_enable_low_power(
&pwrmgr, kDifPwrmgrWakeupRequestSourceFive,
kDifPwrmgrDomainOptionUsbClockInActivePower);
LOG_INFO("TEST: Issue WFI to enter deep sleep");
wait_for_interrupt();
} else if (pwrmgr_testutils_is_wakeup_reason(
&pwrmgr, kDifPwrmgrWakeupRequestSourceFive)) {
// Fail if some measurements are enabled.
CHECK(clkmgr_testutils_check_measurement_enables(&clkmgr,
kDifToggleDisabled));
// Check measurement control regwen is enabled.
dif_toggle_t state;
CHECK_DIF_OK(dif_clkmgr_measure_ctrl_get_enable(&clkmgr, &state));
CHECK(state == kDifToggleEnabled);
LOG_INFO("Check for all clock measurements disabled done");
// Check we have a measurement error for the main clock.
dif_clkmgr_recov_err_codes_t err_codes;
CHECK_DIF_OK(dif_clkmgr_recov_err_code_get_codes(&clkmgr, &err_codes));
CHECK(err_codes == kDifClkmgrRecovErrTypeMainMeas,
"expected main clk measurement error, but got 0x%x", err_codes);
// Clear measurement errors.
CHECK_DIF_OK(dif_clkmgr_recov_err_code_clear_codes(&clkmgr, UINT32_MAX));
LOG_INFO("TEST: one more measurement");
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);
LOG_INFO("TEST: done");
return true;
} else { // error
dif_pwrmgr_wakeup_reason_t wakeup_reason;
CHECK_DIF_OK(dif_pwrmgr_wakeup_reason_get(&pwrmgr, &wakeup_reason));
LOG_ERROR("Unexpected wakeup detected: type = %d, request_source = %d",
wakeup_reason.types, wakeup_reason.request_sources);
return false;
}
return false;
}