blob: 8010b55a17fab40b772968eab4adc6104a6b6dc8 [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_pwrmgr.h"
#include "sw/device/lib/dif/dif_rv_plic.h"
#include "sw/device/lib/dif/dif_sensor_ctrl.h"
#include "sw/device/lib/runtime/ibex.h"
#include "sw/device/lib/runtime/irq.h"
#include "sw/device/lib/runtime/log.h"
#include "sw/device/lib/testing/pwrmgr_testutils.h"
#include "sw/device/lib/testing/rv_plic_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"
#include "sensor_ctrl_regs.h" // Generated.
#include "sw/device/lib/testing/autogen/isr_testutils.h"
OTTF_DEFINE_TEST_CONFIG();
static dif_pwrmgr_t pwrmgr;
static dif_rv_plic_t plic;
static plic_isr_ctx_t plic_ctx = {.rv_plic = &plic,
.hart_id = kTopEarlgreyPlicTargetIbex0};
static pwrmgr_isr_ctx_t pwrmgr_isr_ctx = {
.pwrmgr = &pwrmgr,
.plic_pwrmgr_start_irq_id = kTopEarlgreyPlicIrqIdPwrmgrAonWakeup,
.expected_irq = kDifPwrmgrIrqWakeup,
.is_only_irq = true};
static bool get_wakeup_status(void) {
dif_pwrmgr_request_sources_t wake_req = -1;
CHECK_DIF_OK(dif_pwrmgr_get_current_request_sources(
&pwrmgr, kDifPwrmgrReqTypeWakeup, &wake_req));
return (wake_req > 0);
}
/**
* External interrupt handler.
*/
void ottf_external_isr(void) {
dif_pwrmgr_irq_t irq_id;
top_earlgrey_plic_peripheral_t peripheral;
isr_testutils_pwrmgr_isr(plic_ctx, pwrmgr_isr_ctx, &peripheral, &irq_id);
// Check that both the peripheral and the irq id is correct
CHECK(peripheral == kTopEarlgreyPlicPeripheralPwrmgrAon,
"IRQ peripheral: %d is incorrect", peripheral);
CHECK(irq_id == kDifPwrmgrIrqWakeup, "IRQ ID: %d is incorrect", irq_id);
}
bool test_main(void) {
dif_sensor_ctrl_t sensor_ctrl;
// Enable global and external IRQ at Ibex.
irq_global_ctrl(true);
irq_external_ctrl(true);
// Initialize the PLIC.
mmio_region_t plic_base_addr =
mmio_region_from_addr(TOP_EARLGREY_RV_PLIC_BASE_ADDR);
CHECK_DIF_OK(dif_rv_plic_init(plic_base_addr, &plic));
// Initialize pwrmgr
CHECK_DIF_OK(dif_pwrmgr_init(
mmio_region_from_addr(TOP_EARLGREY_PWRMGR_AON_BASE_ADDR), &pwrmgr));
// Initialize sensor_ctrl
CHECK_DIF_OK(dif_sensor_ctrl_init(
mmio_region_from_addr(TOP_EARLGREY_SENSOR_CTRL_BASE_ADDR), &sensor_ctrl));
// Enable all the AON interrupts used in this test.
rv_plic_testutils_irq_range_enable(&plic, kTopEarlgreyPlicTargetIbex0,
kTopEarlgreyPlicIrqIdPwrmgrAonWakeup,
kTopEarlgreyPlicIrqIdPwrmgrAonWakeup);
// Enable pwrmgr interrupt
CHECK_DIF_OK(dif_pwrmgr_irq_set_enabled(&pwrmgr, 0, kDifToggleEnabled));
// Capture the number of events to test
uint32_t sensor_ctrl_events = SENSOR_CTRL_PARAM_NUM_ALERT_EVENTS;
dif_pwrmgr_domain_config_t sleep_config =
kDifPwrmgrDomainOptionMainPowerInLowPower;
for (size_t i = 0; i < sensor_ctrl_events; ++i) {
LOG_INFO("Testing sensor_ctrl event %d", i);
// Setup event trigger
CHECK_DIF_OK(dif_sensor_ctrl_set_ast_event_trigger(&sensor_ctrl, i,
kDifToggleEnabled));
// Normal sleep.
pwrmgr_testutils_enable_low_power(&pwrmgr, kDifPwrmgrWakeupRequestSourceSix,
sleep_config);
// Enter low power mode.
LOG_INFO("Issue WFI to enter sleep");
wait_for_interrupt();
// Wakeup from sleep.
LOG_INFO("Wake from sleep");
dif_sensor_ctrl_events_t events;
CHECK_DIF_OK(dif_sensor_ctrl_get_recov_events(&sensor_ctrl, &events));
if (events != (1 << i)) {
LOG_ERROR("Recoverable event 0x%x does not match expectation %d", events,
i);
}
// clear event trigger
CHECK_DIF_OK(dif_sensor_ctrl_set_ast_event_trigger(&sensor_ctrl, i,
kDifToggleDisabled));
// since there is synchronization delay to trigger clearing and actual event
// de-assertion, clear and poll until it is finished before moving on
while (events) {
CHECK_DIF_OK(dif_sensor_ctrl_clear_recov_event(&sensor_ctrl, i));
CHECK_DIF_OK(dif_sensor_ctrl_get_recov_events(&sensor_ctrl, &events));
}
// ensure the de-asserted events have cleared from the wakeup pipeline
// within 30us
IBEX_SPIN_FOR(!get_wakeup_status(), 30);
}
return true;
}