rt-thread/bsp/rockchip/common/drivers/interrupt.c

260 lines
6.2 KiB
C

/**
* Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd
*
* SPDX-License-Identifier: Apache-2.0
******************************************************************************
* @file interrupt.c
* @version V0.1
* @brief interrupt interface for rt-thread
*
* Change Logs:
* Date Author Notes
* 2019-05-08 Cliff.Chen first implementation
*
******************************************************************************
*/
#include <rthw.h>
#include "hal_base.h"
#if defined(ARCH_ARM_CORTEX_M0) || defined(ARCH_ARM_CORTEX_M3) || defined(ARCH_ARM_CORTEX_M4) || defined(ARCH_ARM_CORTEX_M7)
#if EXT_INTERRUPT
struct rk_intc
{
void *intc_base;
rt_isr_handler_t irq_handler;
};
static rt_isr_handler_t ext_vector[NUM_EXT_INTERRUPTS];
static void intc_irq_dispatch(void *intc, uint32_t offset)
{
uint32_t i, irq_no;
for (i = 0; i < NUM_EXT_INTERRUPTS; i++)
{
if (HAL_INTC_GetFinalStatus(intc, i))
{
irq_no = i + offset * NUM_INT_PER_CONTROLLER;
ext_vector[irq_no](NUM_INTERRUPTS + irq_no, NULL);
}
}
}
#define DEFINE_RK_INTC_IRQ(ID) \
static void rk_intc##ID##_irq_dispatch(int irq, void *param); \
static struct rk_intc rk_intc##ID = \
{ \
.intc_base = INTC##ID, \
.irq_handler = rk_intc##ID##_irq_dispatch, \
}; \
static void rk_intc##ID##_irq_dispatch(int irq, void *param) \
{ \
intc_irq_dispatch(INTC##ID, ID); \
}
#ifdef INTC0
DEFINE_RK_INTC_IRQ(0);
#endif
#ifdef INTC1
DEFINE_RK_INTC_IRQ(1);
#endif
#ifdef INTC2
DEFINE_RK_INTC_IRQ(2);
#endif
#ifdef INTC3
DEFINE_RK_INTC_IRQ(3);
#endif
static struct rk_intc *rk_intc_table[] =
{
#ifdef INTC0
&rk_intc0,
#endif
#ifdef INTC1
&rk_intc1,
#endif
#ifdef INTC2
&rk_intc2,
#endif
#ifdef INTC3
&rk_intc3,
#endif
};
static void rk_intc_init(void)
{
uint32_t i;
memset(ext_vector, 0, sizeof(ext_vector));
for (i = 0; i < HAL_ARRAY_SIZE(rk_intc_table); i++)
{
HAL_NVIC_SetIRQHandler(INTC0_IRQn + i, (NVIC_IRQHandler)rk_intc_table[i]->irq_handler);
HAL_NVIC_EnableIRQ(INTC0_IRQn + i);
HAL_INTC_EnableAllRQ(rk_intc_table[i]->intc_base);
}
}
static void rk_intc_mask(uint32_t vector)
{
uint32_t intc, irq;
if (vector >= TOTAL_INTERRUPTS)
return;
if (vector < NUM_INTERRUPTS)
HAL_NVIC_DisableIRQ(vector);
else
{
intc = (vector - NUM_INTERRUPTS) / NUM_INT_PER_CONTROLLER;
irq = (vector - NUM_INTERRUPTS) % NUM_INT_PER_CONTROLLER;
if (intc >= HAL_ARRAY_SIZE(rk_intc_table))
return;
HAL_INTC_MaskIRQ(rk_intc_table[intc]->intc_base, irq);
}
}
static void rk_intc_unmask(uint32_t vector)
{
uint32_t intc, irq;
if (vector >= TOTAL_INTERRUPTS)
return;
if (vector < NUM_INTERRUPTS)
HAL_NVIC_EnableIRQ(vector);
else
{
intc = (vector - NUM_INTERRUPTS) / NUM_INT_PER_CONTROLLER;
irq = (vector - NUM_INTERRUPTS) % NUM_INT_PER_CONTROLLER;
if (intc >= HAL_ARRAY_SIZE(rk_intc_table))
return;
HAL_INTC_UnmaskIRQ(rk_intc_table[intc]->intc_base, irq);
}
}
#endif /* end of EXT_INTERRUPT */
#ifdef RT_USING_PROF_IRQ
#define IRQ_AVG_COUNT 200
struct irq_summry
{
uint32_t count;
uint32_t start;
uint32_t time_total;
uint32_t time_avg;
uint32_t time_max;
};
static struct irq_summry g_irq_prof[TOTAL_INTERRUPTS];
static void irq_enter_hook(void)
{
uint32_t irq;
irq = __get_IPSR() - 16;
g_irq_prof[irq].count++;
g_irq_prof[irq].start = HAL_TIMER_GetCount(SYS_TIMER);
}
static void irq_leave_hook(void)
{
uint32_t time_cur, end, irq;
irq = __get_IPSR() - 16;
end = HAL_TIMER_GetCount(SYS_TIMER);
if (end < g_irq_prof[irq].start)
end += PLL_INPUT_OSC_RATE;
time_cur = end - g_irq_prof[irq].start;
g_irq_prof[irq].time_total += time_cur;
g_irq_prof[irq].time_max =
g_irq_prof[irq].time_max > time_cur ? g_irq_prof[irq].time_max : time_cur;
if (g_irq_prof[irq].count > 0 &&
g_irq_prof[irq].count % IRQ_AVG_COUNT == 0)
{
g_irq_prof[irq].time_avg = g_irq_prof[irq].time_total / IRQ_AVG_COUNT;
g_irq_prof[irq].time_total = 0;
}
}
static void dump_irq_summry(int argc, char **argv)
{
uint32_t i;
rt_kprintf("IRQ COUNT AVG MAX\n");
for (i = 0; i < NUM_INTERRUPTS; i++)
{
rt_kprintf("%03d %08d %08d %08d\n", i, g_irq_prof[i].count,
g_irq_prof[i].time_avg,
g_irq_prof[i].time_max);
}
}
#ifdef RT_USING_FINSH
#include <finsh.h>
MSH_CMD_EXPORT(dump_irq_summry, dump irq summry);
#endif
#endif /* end of RT_USING_PROF_IRQ */
void rt_hw_interrupt_init(void)
{
uint32_t i;
for (i = 0; i < NUM_INTERRUPTS; i++)
{
HAL_NVIC_SetPriority(i, NVIC_PERIPH_PRIO_DEFAULT, NVIC_PERIPH_SUB_PRIO_DEFAULT);
}
#if EXT_INTERRUPT
rk_intc_init();
#endif
#ifdef RT_USING_PROF_IRQ
rt_interrupt_enter_sethook(irq_enter_hook);
rt_interrupt_leave_sethook(irq_leave_hook);
#endif
}
void rt_hw_interrupt_mask(int vector)
{
#if EXT_INTERRUPT
rk_intc_mask(vector);
#else
HAL_NVIC_DisableIRQ(vector);
#endif
}
void rt_hw_interrupt_umask(int vector)
{
#if EXT_INTERRUPT
rk_intc_unmask(vector);
#else
HAL_NVIC_EnableIRQ(vector);
#endif
}
rt_isr_handler_t rt_hw_interrupt_install(int vector,
rt_isr_handler_t handler,
void *param,
const char *name)
{
#if EXT_INTERRUPT
if (vector < NUM_INTERRUPTS)
HAL_NVIC_SetIRQHandler(vector, (NVIC_IRQHandler)handler);
else
ext_vector[vector - NUM_INTERRUPTS] = handler;
#else
HAL_NVIC_SetIRQHandler(vector, (NVIC_IRQHandler)handler);
#endif
return handler;
}
#endif /* end of defined(ARCH_ARM_CORTEX_M0) || defined(ARCH_ARM_CORTEX_M3) || defined(ARCH_ARM_CORTEX_M4) || defined(ARCH_ARM_CORTEX_M7) */