lock_lfvx/bk_idk/middleware/arch/riscv/arch_interrupt.c
2025-10-10 16:07:00 +08:00

218 lines
5.7 KiB
C
Executable File

// Copyright 2020-2021 Beken
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <sdkconfig.h>
#include <stdio.h>
#include "arch_interrupt.h"
#include "platform.h"
#include "BK7256_RegList.h"
#if CONFIG_FREERTOS_TRACE
#include "trcRecorder.h"
#endif
#define INT_NUMBER_MAX (64)
#define INT_PRIORITY_PLIC 0x01
#define INT_PRIORITY_MASK 0x07
#define REG_PLIC_PENDING_STATUS_GROUP1 (0xe4001000) //we can optimize this code with PLIC driver.
#define REG_PLIC_PENDING_STATUS_GROUP2 (0xe4001004)
#define CONFIG_NEST_INT_TEST 0
interrupt_handle_p p_intn_func_handle[INT_NUMBER_MAX];
volatile unsigned int g_enter_interrupt_nest = 0;
unsigned int arch_get_interrupt_nest_cnt(void) {
return g_enter_interrupt_nest;
}
#if (CONFIG_NEST_INT_TEST)
#define INT_SRC_UART0 (4)
#define SYS_DELAY_TIME_1MS (17000UL)
volatile unsigned int g_test_nest_count = 1;
extern void sys_delay_sync(uint32_t time_count );
#endif
/* At the time of writing, interrupt nesting is not supported, so do not use
the default mext_interrupt() implementation as that enables interrupts. A
version that does not enable interrupts is provided below. THIS INTERRUPT
HANDLER IS SPECIFIC TO FREERTOS WHICH USES PLIC! */
void mext_interrupt_sub(void)
{
unsigned int irq_source = HAL_IRQ_CLAIM(); /// __nds__plic_claim_interrupt();
g_enter_interrupt_nest++;
#if (CONFIG_NEST_INT_TEST)
if (g_enter_interrupt_nest > 1 && g_test_nest_count > 0)
{
os_printf("mext_interrupt: nest count %d, irq_source = %u.\r\n", g_enter_interrupt_nest, irq_source);
g_test_nest_count--;
}
#endif //#if (CONFIG_NEST_INT_TEST)
#if (CONFIG_NEST_INT_SUPPORT)
/* Disable the timer interrupts before
Enable interrupts in general to allow nested
*/
HAL_TI_DISABLE();
/* Enable interrupts in general to allow nested */
HAL_INT_ENABLE();
#endif // #if (CONFIG_NEST_INT_SUPPORT)
if (irq_source != 0 && irq_source < INT_NUMBER_MAX
&& p_intn_func_handle[irq_source] != NULL) {
#if (CONFIG_FREERTOS_TRACE)
xTraceISRBegin(xGetTraceISRHandle(irq_source));
#endif
/* Do interrupt handler */
p_intn_func_handle[irq_source]();
#if (CONFIG_FREERTOS_TRACE)
xTraceISREnd(0);
#endif
#if (CONFIG_NEST_INT_TEST)
if (irq_source != INT_SRC_UART0 && g_test_nest_count != 0)
{
sys_delay_sync(SYS_DELAY_TIME_1MS);
}
#endif //#if (CONFIG_NEST_INT_TEST)
} else {
//print irq status
os_printf("ERROR: func %s, irq_source = %u.\r\n", __func__, irq_source);
if (irq_source < INT_NUMBER_MAX) {
os_printf("ERROR: func %s, p_intn_func_handle = %p.\r\n", __func__, p_intn_func_handle[irq_source]);
}
}
#if (CONFIG_NEST_INT_SUPPORT)
/* Disable interrupt in general to restore context */
HAL_INT_DISABLE();
/* Restore the timer interrupts after
interrupts complete handle
*/
if (g_enter_interrupt_nest == 1) {
HAL_TI_ENABLE();
}
#endif // #if (CONFIG_NEST_INT_SUPPORT)
g_enter_interrupt_nest--;
HAL_IRQ_COMPLETE(irq_source);
}
extern u32 arch_get_int_status(void);
void mext_interrupt(void)
{
while(arch_get_int_status() & UIP_UEIP)
{
mext_interrupt_sub();
}
}
void arch_interrupt_set_priority(arch_int_src_t int_number, uint32_t int_priority)
{
if(int_number > 0 && int_number < INT_NUMBER_MAX) {
//set Priority for int. Priority level must be set > 0 and <=7
HAL_IRQ_SET_PRIORITY(int_number, int_priority & INT_PRIORITY_MASK);
}
return;
}
void arch_interrupt_register_int(arch_int_src_t int_number, int_group_isr_t isr_callback)
{
if((int_number > (INT_ID_MAX-1))|| isr_callback == NULL)
{
return;
}
p_intn_func_handle[int_number] = isr_callback;
HAL_IRQ_ENABLE(int_number);
}
void arch_interrupt_unregister_int(arch_int_src_t int_number)
{
if(int_number > (INT_ID_MAX-1))
{
return;
}
p_intn_func_handle[int_number] = NULL;
HAL_IRQ_DISABLE(int_number);
arch_interrupt_set_priority(int_number, 0);
}
extern void riscv_set_mtimercmp(u64 new_time);
extern u64 riscv_get_mtimer(void);
extern u64 riscv_get_mtimercmp(void);
//specify:low voltage process can't be interrupt or the system can't response external interrupt after wakeup.
void mtimer_reset_next_tick(uint32_t minimum_offset)
{
u64 time_cmp = riscv_get_mtimercmp();
u64 cur_time = riscv_get_mtimer();
if(time_cmp < cur_time + minimum_offset)
{
riscv_set_mtimercmp(cur_time + minimum_offset);
}
}
bool mtimer_is_timeout()
{
u64 time_cmp = riscv_get_mtimercmp();
u64 cur_time = riscv_get_mtimer();
return (time_cmp <= cur_time);
}
void arch_interrupt_init(void)
{
HAL_INT_DISABLE(); /* Disable interrupts in general. */
HAL_SI_DISABLE(); /* software interrupt. */
HAL_EI_ENABLE(); /* external interrupt. */
HAL_TI_ENABLE(); /* timer interrupt. */
#if (CONFIG_NEST_INT_TEST)
// arch_interrupt_set_priority(INT_SRC_UART0, 2); // should update the priority in ICU_MP
#endif //#if (CONFIG_NEST_INT_TEST)
}
bk_err_t arch_isr_entry_init(void)
{
arch_interrupt_init();
return BK_OK;
}
uint64_t arch_get_plic_pending_status(void)
{
uint64_t plic_pend1 = *(volatile uint32 *)(REG_PLIC_PENDING_STATUS_GROUP1);
uint64_t plic_pend2 = *(volatile uint32 *)(REG_PLIC_PENDING_STATUS_GROUP2);
uint64_t plic_pending_status = (plic_pend2 << 32) | plic_pend1;
return plic_pending_status;
}