blob: 399fbc934a14f595471975b2b148af6b382c04d6 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
${gencmd}
<%
irq_peripheral_names = sorted({p.name for p in helper.irq_peripherals})
enabled_peripherals = ['aes', 'alert_handler', 'clkmgr', 'csrng', 'edn',
'entropy_src', 'gpio', 'hmac', 'i2c', 'keymgr', 'kmac',
'lc_ctrl', 'otbn', 'otp_ctrl', 'pinmux', 'pwrmgr',
'rstmgr', 'spi_device', 'sram_ctrl', 'uart', 'usbdev']
parameterized_peripherals = ['alert_handler']
def comment(n):
return '' if n in enabled_peripherals else '// '
%>\
#include "sw/device/lib/base/freestanding/limits.h"
#include "sw/device/lib/base/mmio.h"
#include "sw/device/lib/dif/dif_rv_plic.h"
% for n in irq_peripheral_names:
${comment(n)}#include "sw/device/lib/dif/dif_${n}.h"
% endfor
#include "sw/device/lib/handler.h"
#include "sw/device/lib/irq.h"
#include "sw/device/lib/runtime/log.h"
#include "sw/device/lib/testing/check.h"
#include "sw/device/lib/testing/rv_plic_testutils.h"
#include "sw/device/lib/testing/test_framework/test_main.h"
#include "sw/device/lib/testing/test_framework/test_status.h"
#include "sw/device/tests/plic_all_irqs_test_helper.h"
% for p in parameterized_peripherals:
${comment(p)}#include "${p}_regs.h" // Generated.
% endfor
#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
% for p in helper.irq_peripherals:
${comment(p.name)}static dif_${p.name}_t ${p.inst_name};
% endfor
static dif_rv_plic_t plic;
static const top_earlgrey_plic_target_t kHart = kTopEarlgreyPlicTargetIbex0;
/**
* Flag indicating which peripheral is under test.
*
* Declared volatile because it is referenced in the main program flow as well
* as the ISR.
*/
static volatile top_earlgrey_plic_peripheral_t peripheral_expected;
/**
* Flags indicating the IRQ expected to have triggered and serviced within the
* peripheral.
*
* Declared volatile because it is referenced in the main program flow as well
* as the ISR.
*/
% for n in irq_peripheral_names:
${comment(n)}static volatile dif_${n}_irq_t ${n}_irq_expected;
${comment(n)}static volatile dif_${n}_irq_t ${n}_irq_serviced;
% endfor
/**
* Provides external IRQ handling for this test.
*
* This function overrides the default external IRQ handler in
* `sw/device/lib/handler.h`.
*/
void handler_irq_external(void) {
// Find which interrupt fired at PLIC by claiming it.
dif_rv_plic_irq_id_t plic_irq_id;
CHECK(dif_rv_plic_irq_claim(&plic, kHart, &plic_irq_id) == kDifRvPlicOk);
// Check if it is the right peripheral.
top_earlgrey_plic_peripheral_t peripheral = (top_earlgrey_plic_peripheral_t)
top_earlgrey_plic_interrupt_for_peripheral[plic_irq_id];
CHECK(peripheral == peripheral_expected,
"Interrupt from incorrect peripheral: exp = %d, obs = %d",
peripheral_expected, peripheral);
switch (peripheral) {
% for p in helper.irq_peripherals:
${comment(p.name)}case ${p.plic_name}:
${comment(p.name)} PERIPHERAL_ISR(${p.name}, ${p.inst_name}, ${p.plic_start_irq});
${comment(p.name)} break;
% endfor
default:
LOG_FATAL("ISR is not implemented!");
test_status_set(kTestStatusFailed);
}
// Complete the IRQ at PLIC.
CHECK(dif_rv_plic_irq_complete(&plic, kHart, plic_irq_id) == kDifRvPlicOk);
}
/**
* Initializes the handles to all peripherals.
*/
static void peripherals_init(void) {
dif_alert_handler_params_t alert_handler_params = {
.alert_count = ALERT_HANDLER_PARAM_N_ALERTS,
.escalation_signal_count = ALERT_HANDLER_PARAM_N_ESC_SEV};
% for p in helper.irq_peripherals:
% if p.name in parameterized_peripherals:
${comment(p.name)}PERIPHERAL_INIT_WITH_PARAMS(${p.name}, ${p.name}_params, ${p.inst_name}, ${p.base_addr_name});
% else:
${comment(p.name)}PERIPHERAL_INIT(${p.name}, ${p.inst_name}, ${p.base_addr_name});
% endif
% endfor
mmio_region_t base_addr =
mmio_region_from_addr(TOP_EARLGREY_RV_PLIC_BASE_ADDR);
CHECK(dif_rv_plic_init((dif_rv_plic_params_t){.base_addr = base_addr},
&plic) == kDifRvPlicOk);
}
/**
* Clears pending IRQs in all peripherals.
*/
static void peripheral_irqs_clear(void) {
% for p in helper.irq_peripherals:
${comment(p.name)}PERIPHERAL_IRQS_CLEAR(${p.inst_name});
% endfor
}
/**
* Enables all IRQs in all peripherals.
*/
static void peripheral_irqs_enable(void) {
% for p in helper.irq_peripherals:
${comment(p.name)}PERIPHERAL_IRQS_ENABLE(${p.name}, ${p.inst_name});
% endfor
}
/**
* Triggers all IRQs in all peripherals one by one.
*
* Walks through all instances of all peripherals and triggers an interrupt one
* by one. Instead of invoking WFI, it waits for a couple of cycles with nops,
* and then checks if the right interrupt was handled. The ISR which the CPU
* jumps into checks if the correct interrupt from the right instance triggered.
*/
static void peripheral_irqs_trigger(void) {
% for p in helper.irq_peripherals:
${comment(p.name)}PERIPHERAL_IRQS_TRIGGER(${p.name}, ${p.inst_name}, ${p.plic_name},
${comment(p.name)} ${p.start_irq}, ${p.end_irq});
% endfor
}
const test_config_t kTestConfig;
bool test_main(void) {
irq_global_ctrl(true);
irq_external_ctrl(true);
peripherals_init();
rv_plic_testutils_irq_range_enable(&plic, kHart,
kTopEarlgreyPlicIrqIdNone + 1, kTopEarlgreyPlicIrqIdLast);
peripheral_irqs_clear();
peripheral_irqs_enable();
peripheral_irqs_trigger();
return true;
}