| /* |
| * 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; |
| } |