blob: a31788980be84541bd4c4929e0c6b009901e9cb7 [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/mmio.h"
#include "sw/device/lib/dif/dif_aon_timer.h"
#include "sw/device/lib/dif/dif_pwrmgr.h"
#include "sw/device/lib/runtime/log.h"
#include "sw/device/lib/testing/check.h"
#include "sw/device/lib/testing/test_framework/test_main.h"
#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
static const dif_pwrmgr_wakeup_reason_t kWakeUpReasonTest = {
.types = kDifPwrmgrWakeupTypeRequest,
.request_sources = kDifPwrmgrWakeupRequestSourceFive,
};
static const dif_pwrmgr_wakeup_reason_t kWakeUpReasonPor = {
.types = 0,
.request_sources = 0,
};
const test_config_t kTestConfig;
bool compare_wakeup_reasons(const dif_pwrmgr_wakeup_reason_t *lhs,
const dif_pwrmgr_wakeup_reason_t *rhs) {
return lhs->types == rhs->types &&
lhs->request_sources == rhs->request_sources;
}
void aon_timer_wakeup_config(dif_aon_timer_t *aon_timer,
uint32_t wakeup_threshold) {
// Make sure that wake-up timer is stopped.
CHECK(dif_aon_timer_wakeup_stop(aon_timer) == kDifAonTimerOk);
// Make sure the wake-up IRQ is cleared to avoid false positive.
CHECK(dif_aon_timer_irq_acknowledge(
aon_timer, kDifAonTimerIrqWakeupThreshold) == kDifAonTimerOk);
bool is_pending;
CHECK(dif_aon_timer_irq_is_pending(aon_timer, kDifAonTimerIrqWakeupThreshold,
&is_pending) == kDifAonTimerOk);
CHECK(!is_pending);
CHECK(dif_aon_timer_wakeup_start(aon_timer, wakeup_threshold, 0) ==
kDifAonTimerOk);
}
bool test_main(void) {
dif_pwrmgr_t pwrmgr;
dif_aon_timer_t aon_timer;
// Initialize pwrmgr
CHECK(dif_pwrmgr_init(
(dif_pwrmgr_params_t){
.base_addr =
mmio_region_from_addr(TOP_EARLGREY_PWRMGR_AON_BASE_ADDR),
},
&pwrmgr) == kDifPwrmgrOk);
// Assuming the chip hasn't slept yet, wakeup reason should be empty.
dif_pwrmgr_wakeup_reason_t wakeup_reason;
CHECK(dif_pwrmgr_wakeup_reason_get(&pwrmgr, &wakeup_reason) == kDifPwrmgrOk);
if (compare_wakeup_reasons(&wakeup_reason, &kWakeUpReasonPor)) {
LOG_INFO("Powered up for the first time, begin test");
// Initialize aon_timer
dif_aon_timer_params_t params = {
.base_addr =
mmio_region_from_addr(TOP_EARLGREY_AON_TIMER_AON_BASE_ADDR),
};
CHECK(dif_aon_timer_init(params, &aon_timer) == kDifAonTimerOk);
// Issue a wakeup singal in ~150us through the AON timer.
//
// At 200kHz, threshold of 30 is equal to 150us. There is an additional
// ~4 cycle overhead for the CSR value to synchronize with the AON clock.
// We should expect the wake up to trigger in ~170us. This is sufficient
// time to allow pwrmgr config and the low power entry on WFI to complete.
//
// Adjust the threshold for Verilator since it runs on different clock
// frequencies.
uint32_t wakeup_threshold = 30;
if (kDeviceType == kDeviceSimVerilator) {
wakeup_threshold = 300;
}
aon_timer_wakeup_config(&aon_timer, wakeup_threshold);
// Enable low power on the next WFI with default settings.
// All clocks and power domains are turned off during low power.
dif_pwrmgr_domain_config_t config;
// Issue #6504: USB clock in active power must be left enabled.
config = kDifPwrmgrDomainOptionUsbClockInActivePower;
CHECK(dif_pwrmgr_set_request_sources(&pwrmgr, kDifPwrmgrReqTypeWakeup,
kDifPwrmgrWakeupRequestSourceFive) ==
kDifPwrmgrConfigOk);
CHECK(dif_pwrmgr_set_domain_config(&pwrmgr, config) == kDifPwrmgrConfigOk);
CHECK(dif_pwrmgr_low_power_set_enabled(&pwrmgr, kDifPwrmgrToggleEnabled) ==
kDifPwrmgrConfigOk);
// Enter low power mode.
wait_for_interrupt();
} else if (compare_wakeup_reasons(&wakeup_reason, &kWakeUpReasonTest)) {
LOG_INFO("Aon timer wakeup detected");
return true;
} else {
LOG_ERROR("Unexpected wakeup detected: type = %d, request_source = %d",
wakeup_reason.types, wakeup_reason.request_sources);
return false;
}
return false;
}