espressif_tinyusb/hw/mcu/allwinner/f1c100s/machine/f1c100s-intc.c

174 lines
3.6 KiB
C

// Originally designed by Hong Xuyao
#include <stdint.h>
#include <stdio.h>
#include <f1c100s-irq.h>
#include <arm32.h>
#define __irq __attribute__ ((interrupt ("IRQ")))
#ifndef __IO
#define __IO volatile
#endif
typedef struct {
__IO uint32_t INTC_VECTOR_REG; // 0x00
__IO uint32_t INTC_BASE_ADDR_REG; // 0x04
uint32_t resv1[1]; // 0x08
__IO uint32_t NMI_INT_CTRL_REG; // 0x0c
__IO uint32_t INTC_PEND_REG[2]; // 0x10
uint32_t resv2[2]; // 0x18
__IO uint32_t INTC_EN_REG[2]; // 0x20
uint32_t resv3[2]; // 0x28
__IO uint32_t INTC_MASK_REG[2]; // 0x30
uint32_t resv4[2]; // 0x38
__IO uint32_t INTC_RESP_REG[2]; // 0x40
uint32_t resv5[2]; // 0x48
__IO uint32_t INTC_FF_REG[2]; // 0x50
uint32_t resv6[2]; // 0x58
__IO uint32_t INTC_PRIO_REG[4]; // 0x60
} INTC_TypeDef;
#ifndef COUNTOF
#define COUNTOF(ar) (sizeof(ar)/sizeof(ar[0]))
#endif
#define INTC ((INTC_TypeDef*)0x01C20400)
static IRQHandleTypeDef irq_table[64] __attribute__((used, aligned(32)));
void arm32_do_irq(struct arm_regs_t * regs)
{
uint8_t nIRQ = f1c100s_intc_get_nirq();
// ForceIRQ flag must be cleared by ISR
// Otherwise ISR will be entered repeatedly
INTC->INTC_FF_REG[nIRQ / 32] &= ~(1 << nIRQ);
// Call the drivers ISR
f1c100s_intc_dispatch(nIRQ);
// Clear pending at the end of ISR
f1c100s_intc_clear_pend(nIRQ);
}
void arm32_do_fiq(struct arm_regs_t * regs)
{
// Call the drivers ISR
f1c100s_intc_dispatch(0);
// Clear pending at the end of ISR.
f1c100s_intc_clear_pend(0);
}
/*
* Read active IRQ number
* @return: none
*/
uint8_t f1c100s_intc_get_nirq(void)
{
return ((INTC->INTC_VECTOR_REG >> 2) & 0x3F);
}
/*
* Execute ISR corresponding to IRQ number
* @nIRQ: IRQ number
* @return: none
*/
void f1c100s_intc_dispatch(uint8_t nIRQ)
{
IRQHandleTypeDef handle = irq_table[nIRQ];
if (handle)
handle();
}
/*
* Set handler function for specified IRQ
* @nIRQ: IRQ number
* @handle: Handle function
* @return: none
*/
void f1c100s_intc_set_isr(uint8_t nIRQ, IRQHandleTypeDef handle)
{
if (nIRQ < COUNTOF(irq_table)) {
irq_table[nIRQ] = handle;
}
}
/*
* Enable IRQ
* @nIRQ: IRQ number
* @return: none
*/
void f1c100s_intc_enable_irq(uint8_t nIRQ)
{
INTC->INTC_EN_REG[nIRQ / 32] |= (1 << (nIRQ % 32));
}
/*
* Disable IRQ
* @nIRQ: IRQ number
* @return: none
*/
void f1c100s_intc_disable_irq(uint8_t nIRQ)
{
INTC->INTC_EN_REG[nIRQ / 32] &= ~(1 << (nIRQ % 32));
}
/*
* Mask IRQ
* @nIRQ: IRQ number
* @return: none
*/
void f1c100s_intc_mask_irq(uint8_t nIRQ)
{
INTC->INTC_MASK_REG[nIRQ / 32] |= (1 << (nIRQ % 32));
}
/*
* Unmask IRQ
* @nIRQ: IRQ number
* @return: none
*/
void f1c100s_intc_unmask_irq(uint8_t nIRQ)
{
INTC->INTC_MASK_REG[nIRQ / 32] &= ~(1 << (nIRQ % 32));
}
/*
* Immediately trigger IRQ
* @nIRQ: IRQ number
* @return: none
*/
void f1c100s_intc_force_irq(uint8_t nIRQ)
{
// This bit is to be cleared in IRQ handler
INTC->INTC_FF_REG[nIRQ / 32] = (1 << (nIRQ % 32));
}
/*
* Clear pending flag
* @nIRQ: IRQ number
* @return: none
*/
void f1c100s_intc_clear_pend(uint8_t nIRQ)
{
INTC->INTC_PEND_REG[nIRQ / 32] = (1 << (nIRQ % 32));
}
/*
* Initialize IRQ module
* @return: none
*/
void f1c100s_intc_init(void)
{
INTC->INTC_EN_REG[0] = INTC->INTC_EN_REG[1] = 0;
INTC->INTC_MASK_REG[0] = INTC->INTC_MASK_REG[1] = 0;
INTC->INTC_FF_REG[0] = INTC->INTC_FF_REG[1] = 0;
INTC->INTC_RESP_REG[0] = INTC->INTC_RESP_REG[1] = 0;
INTC->INTC_PEND_REG[0] = INTC->INTC_PEND_REG[1] = ~0UL;
INTC->INTC_BASE_ADDR_REG = 0;
INTC->NMI_INT_CTRL_REG = 0;
for (unsigned int i = 0; i < COUNTOF(irq_table); i++) {
irq_table[i] = 0;
}
}