esp-idf/components/riscv/include/esp_private/interrupt_plic.h

124 wiersze
3.2 KiB
C

/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <assert.h>
#include "esp_attr.h"
#include "soc/interrupt_reg.h"
#include "soc/soc_caps.h"
#include "riscv/csr.h"
#include "sdkconfig.h"
#if SOC_INT_PLIC_SUPPORTED
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Set global masking level. On the PLIC, all interrupt priority levels strictly less than the threshold
* level are masked.
*/
#define RVHAL_INTR_ENABLE_THRESH 1
/**
* @brief Bitmask to enable the vector mode when writing MTVEC CSR.
* Setting mode field to 1 treats `MTVEC` as a vector base address.
*/
#define MTVEC_MODE_CSR 1
/**
* In the case of PLIC, all the interrupt lines are dedicated to external peripherals, so the offset is 0
*/
#define RV_EXTERNAL_INT_COUNT 32
#define RV_EXTERNAL_INT_OFFSET 0
FORCE_INLINE_ATTR void assert_valid_rv_int_num(int rv_int_num)
{
assert(rv_int_num != 0 && "Invalid CPU interrupt number");
}
/**
* @brief Get the enabled interrupts on the current CPU.
*
* @return Bit mask of the enabled interrupts
*/
FORCE_INLINE_ATTR uint32_t rv_utils_intr_get_enabled_mask(void)
{
return REG_READ(INTERRUPT_CORE0_CPU_INT_ENABLE_REG);
}
/**
* @brief Acknowledge an edge interrupt
*
* @param intr_num Interrupt number (from 0 to 31)
*/
FORCE_INLINE_ATTR void rv_utils_intr_edge_ack(uint32_t intr_num)
{
REG_SET_BIT(INTERRUPT_CORE0_CPU_INT_CLEAR_REG, intr_num);
}
/**
* @brief Restore the CPU interrupt level to the value returned by `rv_utils_set_intlevel_regval`.
*
* @param restoreval Former raw interrupt level, it is NOT necessarily a value between 0 and 7, this is hardware and configuration dependent.
*/
FORCE_INLINE_ATTR void rv_utils_restore_intlevel_regval(uint32_t restoreval)
{
REG_WRITE(INTERRUPT_CURRENT_CORE_INT_THRESH_REG, restoreval);
}
/**
* @brief Set the interrupt threshold to `intlevel` while getting the current level.
*
* @param intlevel New raw interrupt level, it is NOT necessarily a value between 0 and 7, this is hardware and configuration dependent.
*
* @return Current raw interrupt level, can be restored by calling `rv_utils_restore_intlevel_regval`.
*/
FORCE_INLINE_ATTR uint32_t rv_utils_set_intlevel_regval(uint32_t intlevel)
{
#if CONFIG_SECURE_ENABLE_TEE
unsigned prv_mode = RV_READ_CSR(CSR_PRV_MODE);
unsigned old_xstatus;
if (prv_mode == PRV_M) {
old_xstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
} else {
old_xstatus = RV_CLEAR_CSR(ustatus, USTATUS_UIE);
}
uint32_t old_thresh = REG_READ(INTERRUPT_CURRENT_CORE_INT_THRESH_REG);
rv_utils_restore_intlevel_regval(intlevel);
if (prv_mode == PRV_M) {
RV_SET_CSR(mstatus, old_xstatus & MSTATUS_MIE);
} else {
RV_SET_CSR(ustatus, old_xstatus & USTATUS_UIE);
}
return old_thresh;
#else
uint32_t old_mstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
uint32_t old_thresh = REG_READ(INTERRUPT_CURRENT_CORE_INT_THRESH_REG);
rv_utils_restore_intlevel_regval(intlevel);
RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE);
return old_thresh;
#endif
}
#ifdef __cplusplus
}
#endif
#endif /* SOC_INT_PLIC_SUPPORTED */