blob: 3dbf781ef4fd63ee0f23bdb75a4f421b83b1a5de [file] [log] [blame]
/*
* Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*/
#include <stdio.h>
#include <FreeRTOS.h>
#include "interrupt_control_pic.h"
#include "common.h"
#include "register.h"
void pic_set_threshold(uint32_t threshold)
{
volatile uint32_t *threshold_ptr = (uint32_t *)(PIC_CTRL_ADDR + PIC_THRESHOLD_OFFSET);
*threshold_ptr = threshold;
}
void pic_enable_interrupt(uint32_t source)
{
volatile uint32_t *current_ptr =
(volatile uint32_t *)(PIC_CTRL_ADDR + PIC_ENABLE_OFFSET +
((source >> 3) & (~0x3)) // Source number divide 32 and then
// multip 4 (bytes)
);
uint32_t current = *current_ptr;
current = current | (1 << (source & 0x1f)); // Only check the least 5 bits
*current_ptr = current;
}
void pic_disable_interrupt(uint32_t source)
{
volatile uint32_t *current_ptr =
(volatile uint32_t *)(PIC_CTRL_ADDR + PIC_ENABLE_OFFSET +
((source >> 3) & (~0x3)) // Source number divide 32 and then
// multip 4 (bytes)
);
uint32_t current = *current_ptr;
current = current & ~((1 << (source & 0x1f))); // Only check the least 5 bits
*current_ptr = current;
}
void pic_set_priority(uint32_t source, uint32_t priority)
{
if (PIC_NUM_PRIORITIES > 0) {
// Each priority reg occupy a word, so multiple 2
volatile uint32_t *priority_ptr =
(volatile uint32_t *)(PIC_CTRL_ADDR + PIC_PRIORITY_OFFSET +
(source
<< PIC_PRIORITY_SHIFT_PER_SOURCE));
*priority_ptr = priority;
}
}
uint32_t pic_claim_interrupt(void)
{
volatile uint32_t *claim_addr = (volatile uint32_t *)(PIC_CTRL_ADDR + PIC_CLAIM_OFFSET);
return *claim_addr;
}
uint32_t pic_check_eip(void)
{
volatile uint32_t *eip_addr = (volatile uint32_t *)(PIC_CTRL_ADDR + PIC_EIP_OFFSET);
return *eip_addr;
}
void pic_complete_interrupt(uint32_t source)
{
volatile uint32_t *claim_addr = (volatile uint32_t *)(PIC_CTRL_ADDR + PIC_CLAIM_OFFSET);
*claim_addr = source;
}
void DefaultInterruptHandler(void)
{
}
int RegisterIrq(uint32_t int_num, uint32_t int_priority, function_ptr_t handler)
{
pic_interrupt_handlers[int_num] = handler;
pic_set_priority(int_num, int_priority);
// pic_enable_interrupt (int_num);
return 0;
}
int UnRegisterIrq(uint32_t int_num)
{
pic_interrupt_handlers[int_num] = DefaultInterruptHandler;
pic_set_priority(int_num, 0);
return 0;
}
int EnableIrq(uint32_t ulIrq)
{
UBaseType_t uxSavedInterruptStatus;
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
pic_enable_interrupt(ulIrq);
portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);
return 0;
}
int DisableIrq(uint32_t ulIrq)
{
UBaseType_t uxSavedInterruptStatus;
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
pic_disable_interrupt(ulIrq);
portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);
return 0;
}
int SetIrqPriority(uint32_t ulIrq, uint32_t ulPri)
{
pic_set_priority(ulIrq, ulPri);
return 0;
}
static unsigned int irq_setting[IRQ_EN_REG_NUM];
/*N205 does not support clear pending irq.*
*Need use work around to clear pending: *
*1. disable irq (MIE) *
*2. store and disable current enable irq *
*3. enable target irq *
*4. claim and complete target irq *
*5. disable target irq *
*6. restore current irq enable setting *
*7. enable irq (MIE)
*/
int ClearPendingIrq(uint32_t ulIrq)
{
unsigned int i;
volatile uint32_t *current_ptr;
unsigned long irq_status;
irq_status = interrupt_status_get();
if (irq_status & 0x1)
interrupt_disable();
for (i = 0; i < IRQ_EN_REG_NUM; i++) {
current_ptr = (volatile uint32_t *)(PIC_CTRL_ADDR + PIC_ENABLE_OFFSET + i * 4);
irq_setting[i] = REG32(current_ptr);
REG32(current_ptr) = 0;
}
pic_enable_interrupt(ulIrq);
i = pic_claim_interrupt();
pic_complete_interrupt(i);
pic_disable_interrupt(ulIrq);
for (i = 0; i < IRQ_EN_REG_NUM; i++) {
current_ptr = (volatile uint32_t *)(PIC_CTRL_ADDR + PIC_ENABLE_OFFSET + i * 4);
REG32(current_ptr) = irq_setting[i];
}
if (irq_status & 0x1)
interrupt_enable();
return 0;
}