mirror of
https://github.com/revyos/th1520-vendor-uboot.git
synced 2026-09-17 12:52:01 +02:00
238 lines
4.5 KiB
C
238 lines
4.5 KiB
C
/*
|
|
* Copyright (C) 2017-2020 Alibaba Group Holding Limited
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <irq_func.h>
|
|
#include <asm/arch/interrupt.h>
|
|
|
|
#define CONFIG_SYS_NUM_IRQS 32
|
|
|
|
#define PCK_INTC ((PCKStruct_INTC)INTC_BASEADDRESS)
|
|
|
|
void mask_irq(int irq);
|
|
void unmask_irq(int irq);
|
|
|
|
static void enter_critical(int *psr);
|
|
static void exit_critical(int psr);
|
|
|
|
|
|
struct IRQ_Handler {
|
|
interrupt_handler_t *handler;
|
|
void *arg;
|
|
};
|
|
|
|
/*
|
|
* PCK_INTC: The base address of interrupt controller registers
|
|
*/
|
|
volatile CKStruct_INTC *icrp = PCK_INTC;
|
|
|
|
static struct IRQ_Handler ckirq_handlers[CONFIG_SYS_NUM_IRQS] = { {0} };
|
|
|
|
int interrupt_init (void)
|
|
{
|
|
#if 0
|
|
/* initialize PR0-PR31, big endian */
|
|
icrp->PR[0] = 0x00010203;
|
|
icrp->PR[1] = 0x04050607;
|
|
icrp->PR[2] = 0x08090a0b;
|
|
icrp->PR[3] = 0x0c0d0e0f;
|
|
icrp->PR[4] = 0x10111213;
|
|
icrp->PR[5] = 0x14151617;
|
|
icrp->PR[6] = 0x18191a1b;
|
|
icrp->PR[7] = 0x1c1d1e1f;
|
|
|
|
icrp->ICR |= ICR_AVE;
|
|
mask_irq(31); /* first mask all the interrupt */
|
|
enable_interrupts();
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Install an interrupt handler
|
|
*/
|
|
void irq_install_handler(int irq, interrupt_handler_t *handler, void *arg)
|
|
{
|
|
int status;
|
|
|
|
if (irq < 0 || irq >= CONFIG_SYS_NUM_IRQS){
|
|
printf("irq_install_handler: bad irq number %d\n", irq);
|
|
return;
|
|
}
|
|
|
|
status = disable_interrupts();
|
|
|
|
ckirq_handlers[irq].handler = handler;
|
|
ckirq_handlers[irq].arg = arg;
|
|
|
|
enable_normalirq(irq);
|
|
|
|
unmask_irq(irq);
|
|
|
|
if (status){
|
|
enable_interrupts();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Free an interrupt handler
|
|
*/
|
|
void irq_free_handler(int irq)
|
|
{
|
|
int status;
|
|
|
|
if (irq < 0 || irq >= CONFIG_SYS_NUM_IRQS) {
|
|
printf("irq_free_handler: bad irq number %d\n", irq);
|
|
return;
|
|
}
|
|
|
|
status = disable_interrupts ();
|
|
|
|
disable_normalirq(irq);
|
|
|
|
mask_irq(irq);
|
|
|
|
ckirq_handlers[irq].handler = NULL;
|
|
ckirq_handlers[irq].arg = NULL;
|
|
|
|
if (status){
|
|
enable_interrupts();
|
|
}
|
|
}
|
|
|
|
void enable_interrupts(void)
|
|
{
|
|
asm("psrset ee,ie");
|
|
}
|
|
|
|
int disable_interrupts(void)
|
|
{
|
|
asm("psrclr ie");
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* This function enables a priority level of normal interrupt.
|
|
* irq: A priority of normal interrupt which between 0 to 31.
|
|
*/
|
|
void enable_normalirq(int irq)
|
|
{
|
|
int psrbk;
|
|
|
|
enter_critical(&psrbk);
|
|
icrp->NIER |= (1 << irq);
|
|
exit_critical(psrbk);
|
|
}
|
|
|
|
/*
|
|
* This function disables a priority level of normal interrupt.
|
|
* irq: A priority of normal interrupt which between 0 to 31.
|
|
*/
|
|
void disable_normalirq(int irq)
|
|
{
|
|
int psrbk;
|
|
|
|
enter_critical(&psrbk);
|
|
icrp->NIER &= ~(1 << irq);
|
|
exit_critical(psrbk);
|
|
}
|
|
|
|
/*
|
|
* This function enables normal interrupt masking.
|
|
*
|
|
* irq: The priority level that would be masked,
|
|
* leading to mask those priority levels below primask.
|
|
*/
|
|
void mask_irq(int irq)
|
|
{
|
|
int temp_icr;
|
|
int psrbk;
|
|
|
|
temp_icr = icrp->ICR;
|
|
|
|
/*
|
|
* This function will be implemented When fast interrupt masking is disabled,
|
|
* or return at once.
|
|
*/
|
|
if((temp_icr &= 0x10000000) == 0x10000000){
|
|
return;
|
|
}
|
|
else{
|
|
enter_critical(&psrbk);
|
|
icrp->ICR &= 0xffe0ffff;
|
|
icrp->ICR |= ((irq & 0x0000001f) << 16);
|
|
icrp->ICR |= ICR_ME;
|
|
exit_critical(psrbk);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This function disables normal interrupt masking.
|
|
*
|
|
* irq: The priority level that would be unmasked.
|
|
*/
|
|
void unmask_irq(int irq)
|
|
{
|
|
int temp_icr;
|
|
int psrbk;
|
|
|
|
temp_icr = icrp->ICR;
|
|
|
|
enter_critical(&psrbk);
|
|
icrp->ICR &= 0xffe0ffff;
|
|
icrp->ICR |= ((irq & 0x0000001f) << 16);
|
|
icrp->ICR &= ~ICR_ME;
|
|
exit_critical(psrbk);
|
|
}
|
|
|
|
/*
|
|
* Execute the interrupt service.
|
|
*
|
|
*irq :
|
|
*RETURN VALUE: None
|
|
*/
|
|
void ck_irq_service(int irq)
|
|
{
|
|
if (irq < 0 || irq >= CONFIG_SYS_NUM_IRQS) {
|
|
printf("ck_irq_service: bad irq number %d\n", irq);
|
|
return;
|
|
}
|
|
|
|
if (ckirq_handlers[irq].handler) {
|
|
mask_irq(irq);
|
|
|
|
ckirq_handlers[irq].handler(ckirq_handlers[irq].arg);
|
|
|
|
unmask_irq(irq);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This function should be called before executing critical code which should not be
|
|
*interrupted by other interrupts
|
|
*
|
|
*INPUT: psr, to store the value of psr
|
|
*RETURN VALUE: None
|
|
*/
|
|
static void enter_critical(int *psr)
|
|
{
|
|
asm volatile ("mfcr %0, psr\n\r"
|
|
"psrclr ie, fe"
|
|
: "=r" (*psr) );
|
|
}
|
|
|
|
/*This function should be called after exiting critical area.
|
|
*
|
|
*INPUT: psr, contain the backup value of psr
|
|
*RETURN VALUE: None
|
|
*/
|
|
static void exit_critical(int psr)
|
|
{
|
|
asm volatile ("mtcr %0, psr"
|
|
:
|
|
:"r"(psr));
|
|
}
|