| /******************************************************************************** |
| * Marvell GPL License Option |
| * |
| * If you received this File from Marvell, you may opt to use, redistribute and/or |
| * modify this File in accordance with the terms and conditions of the General |
| * Public License Version 2, June 1991 (the "GPL License"), a copy of which is |
| * available along with the File in the license.txt file or by writing to the Free |
| * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or |
| * on the worldwide web at http://www.gnu.org/licenses/gpl.txt. |
| * |
| * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY |
| * DISCLAIMED. The GPL License provides additional details about this warranty |
| * disclaimer. |
| ******************************************************************************/ |
| |
| /*
|
| *
|
| * Public C file to initialise the MPCore Interrupt Distributor.
|
| * This file contains one function.
|
| *
|
| * Description:
|
| * This code sets up the primary interrupt controller (GIC) in the MPCore
|
| * to generate an IRQ to CPU 0 or 1
|
| *
|
| * Implementation:
|
| * After the MPCore GIC is initialised with enableMPGIC(), you can use
|
| * setEnableMPGIC() and clearEnableMPGIC() to set and clear interrupt
|
| * sources in the ARM11 MPCore.
|
| *
|
| * Inputs:
|
| * None.
|
| *
|
| * Outputs:
|
| * MPCore Interrupt Distributor registers.
|
| *
|
| * Return Value:
|
| * None.
|
| */
|
| #include "Galois_memmap.h"
|
| #include "soc.h"
|
| #include "apbRegBase.h"
|
| #include "sdio_ctrl/sdmmc_api.h" |
| #include "gicDiag.h"
|
| #include "pic.h"
|
| #include "sdio_ctrl/util.h" |
| #include "lgpl_printf.h" |
|
|
| #ifdef EMMC_DEBUG
|
| #define printf lgpl_printf
|
| #else
|
| #define dbg_printf lgpl_printf |
| #define printf lgpl_printf
|
| #endif
|
|
|
| |
| /* |
| * Macro to remove unused variable warning for function args not used for |
| * specific platform. |
| */ |
| #define UNUSED(var) do { (void)(var); } while(0) |
| |
| #define MASTER_MP_CORE 0
|
|
|
| void writeEnableMPGIC(unsigned int id, unsigned int offset)
|
| {
|
| unsigned int register_number; // which GIC register: 0 = register for IDs 0-31, 1 = register for IDs 32-63
|
| unsigned int bit_position; // bit position in that register: 0 = least significant bit (D0)
|
|
|
| register_number = id / GIC_INTERRUPTS_PER_WORD; // compiler will optimise divide by a power of 2 into shift right
|
| bit_position = id - register_number * GIC_INTERRUPTS_PER_WORD;
|
| offset = offset + register_number * GIC_BYTES_PER_WORD;
|
| GIC_REGISTER(offset) = 1 << bit_position;
|
| }
|
|
|
|
|
| //enable an interrupt: 0 to 63
|
| void setEnableMPGIC(unsigned int id)
|
| {
|
| writeEnableMPGIC(id, GIC_SetEnable0_31_offset);
|
| }
|
|
|
|
|
| //disable an interrupt: 0 to 63
|
| void clearEnableMPGIC(unsigned int id)
|
| {
|
| writeEnableMPGIC(id, GIC_ClearEnable0_31_offset);
|
| }
|
|
|
| //this function turns an interrupt on or off for a particular CPU
|
| //by routing the interrupt to that CPU at distributor interface
|
| //this is only useful for intId >=32,
|
| //for intId <= 32, Int target regs are read-only
|
|
|
| int diag_GICSetInt(int MPid, int intId, int enable)
|
| {
|
| unsigned int reg_num;
|
| unsigned int bit_pos;
|
| unsigned int temp;
|
|
|
| if(intId<32)
|
| {
|
| //dbg_printf(PRN_RES, "Cannot set interrupt target for interrupt id%d(less than 32)\n", intId);
|
| return 1;
|
| }
|
|
|
| reg_num = intId / GIC_CPU_TARGETS_PER_WORD;
|
| bit_pos = (intId % GIC_CPU_TARGETS_PER_WORD)*8;
|
|
|
| //get current value
|
| temp = GIC_REGISTER(GIC_CPUTarget0_3_offset+reg_num*GIC_BYTES_PER_WORD);
|
|
|
| if(enable)
|
| {
|
| //set the bit
|
| temp |= 1<<(bit_pos+MPid);
|
|
|
| if((temp&(0x3<<bit_pos))==0x3)
|
| dbg_printf("Warning: intr %d is sent to both CPUs\n", intId);
|
| }
|
| else
|
| {
|
| //clear the bit
|
| temp &= ~(1<<(bit_pos+MPid));
|
| }
|
|
|
| GIC_REGISTER(GIC_CPUTarget0_3_offset+reg_num*GIC_BYTES_PER_WORD)=temp;
|
| return 0;
|
| }
|
|
|
| //this function initialize interrupt 0 to 63
|
| //1. Distributor Interface
|
| // a) Enable All interrupts.
|
| // b) Do not route any interrupt to CPU0 and CPU1, use this as the control to turn on interrupt at CPU0 or CPU1
|
| // c) All level-sensitive and 1-N (only one CPU will handle the interrupt)
|
| // d) All interrupts have highest priority
|
| //2. CPU Interface
|
| // a) Priority Mask is lowest
|
| // b) Pre-empty All interrupts
|
|
|
| void initMPGIC(void)
|
| {
|
|
|
| unsigned int temp;
|
| unsigned int MPid=0;
|
| UNUSED(temp); |
|
|
| GIC_CPUControl = GIC_CPU_CONTROL_DISABLE; // Disable interrupts in GIC CPU Interface
|
|
|
| if(MPid==MASTER_MP_CORE)
|
| {
|
|
|
| GIC_Control = GIC_CONTROL_DISABLE; // Disable interrupts in GIC Distributor
|
|
|
| GIC_ClearEnable0_31 = GIC_CLEAR_ENABLE_ALL; // Disable all interrupt sources
|
| GIC_ClearEnable32_63 = GIC_CLEAR_ENABLE_ALL;
|
| GIC_ClearEnable64_95 = GIC_CLEAR_ENABLE_ALL;
|
| GIC_ClearEnable96_127 = GIC_CLEAR_ENABLE_ALL;
|
|
|
| GIC_ClearPending0_31 = GIC_CLEAR_PENDING_ALL; // Clear all pending interrupts
|
| GIC_ClearPending32_63 = GIC_CLEAR_PENDING_ALL;
|
| GIC_ClearPending64_95 = GIC_CLEAR_PENDING_ALL;
|
| GIC_ClearPending96_127 = GIC_CLEAR_PENDING_ALL;
|
|
|
| }
|
|
|
| //Note that SetEnable0_31 is banked for each core
|
| GIC_SetEnable0_31 = GIC_SET_ENABLE_ALL; // Enable all interrupt sources
|
| if( MPid==MASTER_MP_CORE)
|
| {
|
| GIC_SetEnable32_63 = GIC_SET_ENABLE_ALL;
|
| GIC_SetEnable64_95 = GIC_SET_ENABLE_ALL;
|
| GIC_SetEnable96_127 = GIC_SET_ENABLE_ALL;
|
| }
|
|
|
| #if 0 //don't need this
|
| GIC_Security0_31 = 0xFFFFFFFF; //all NS interrupts, will generate IRQ
|
| if(MPid==MASTER_MP_CORE)
|
| {
|
| //please check which is IRQ_dHubIntrAvio0 and set it to NS and highest priority
|
| GIC_Security32_63 = 0xFFFFFFFF; //all NS interrupts, will generate IRQ
|
| GIC_Security64_95 = 0xFFFFFFFF; //all NS interrupts, will generate IRQ
|
| GIC_Security96_127 = 0xFFFFFFFF; //all NS interrupts, will generate IRQ
|
|
|
| #if 0
|
| //make IRQ_dHubIntrAvio0 Secure
|
| if(MP_BERLIN_INTR_ID(IRQ_dHubIntrAvio0)<=63)
|
| {
|
| GIC_Security32_63 &= ~(1<<IRQ_dHubIntrAvio0);
|
| }
|
| else if(MP_BERLIN_INTR_ID(IRQ_dHubIntrAvio0)<=95)
|
| {
|
| GIC_Security64_95 &= ~(1<<(IRQ_dHubIntrAvio0&0x1f));
|
| }
|
| else if(MP_BERLIN_INTR_ID(IRQ_dHubIntrAvio0)<=127)
|
| {
|
| GIC_Security96_127 &= ~(1<<(IRQ_dHubIntrAvio0&0x1f));
|
| }
|
| #endif
|
|
|
| }
|
|
|
| if(MPid==MASTER_MP_CORE)
|
| {
|
| // Set all interrupt priorities to high.
|
| for (temp = GIC_Priority0_3_offset; temp <= GIC_Priority124_127_offset; temp += GIC_PRIORITIES_PER_WORD)
|
| {
|
| GIC_REGISTER(temp) = GIC_PRIORITY_HIGH_ALL;
|
| }
|
| // GIC_REGISTER(GIC_Priority64_67_offset) &= 0xFFFF00FF; //make SPI 65 (IRQ_dHubIntrAvio0-33) highest priority
|
|
|
| //set interrupt goes to none of the CPU0, will be turned on later
|
| for (temp = GIC_CPUTarget0_3_offset; temp <= GIC_CPUTarget124_127_offset; temp += GIC_CPU_TARGETS_PER_WORD)
|
| {
|
| GIC_REGISTER(temp) = GIC_CPU_TARGETS_NONE;
|
| }
|
|
|
| // Set all interrupt sources to be level-sensitive and 1-N software model
|
| // 1-N/N-N bit may be obsolete
|
| for (temp = GIC_Configuration32_47_offset; temp <= GIC_Configuration112_127_offset; temp += 4 )
|
| {
|
| GIC_REGISTER(temp) = GIC_CONFIG_ALL_LEVEL_1N;
|
| }
|
|
|
| }
|
|
|
| // These CPU interface registers are banked for each core
|
| // Enable all interrupt priorities (apart from the lowest priority, 0xF)
|
| // Note that bits [3:0] of this register are not implemented but could be in future
|
| GIC_PriorityMask = GIC_PRIORITY_MASK_LOWEST;
|
|
|
| GIC_BinaryPoint = GIC_PREEMPT_ALL; // Enable pre-emption on all interrupts
|
| #endif
|
| //have both Secure and NS interrupt to CPU
|
| //CPU will ack both S and NS interruts
|
| //S interrupts will generate FIQ
|
| GIC_CPUControl = (GIC_CPU_CONTROL_ENABLE
|
| | GIC_CPU_CONTROL_ENABLE_NS
|
| | GIC_CPU_CONTROL_ACKCTL
|
| | GIC_CPU_CONTROL_FIQEN); // Enable interrupts in GIC CPU interface
|
|
|
| if(MPid==MASTER_MP_CORE)
|
| {
|
| GIC_Control = (GIC_CONTROL_ENABLE | GIC_CONTROL_ENABLE_NS); // Enable NS and S interrupts in GIC Distributor
|
| }
|
| }
|
|
|
| //__irq void GIC_IRQ_Handler(void)
|
|
|
| void GIC_IRQ_Handler(void)
|
| {
|
| unsigned int MPCoreInterruptID;
|
|
|
| //GIC_Acknowledge is GIC_REGISTER(0x010C)
|
| //GIC_Acknowledge is effectively banked.
|
| //that is for CPU0 and CPU1, they are really different registers even with same address
|
| MPCoreInterruptID = GIC_Acknowledge; // reading ID from Acknowledge register changes the interrupt from Pending to Active
|
| //dbg_printf(" Gic IRQ received, MPCoreInterruptID = %d\n", MPCoreInterruptID);
|
| //printf(" %s: MPCoreInterruptID = 0x%x\n",__FUNCTION__, MPCoreInterruptID);
|
| switch ((MPCoreInterruptID & GIC_INT_ACK_MASK))
|
| {
|
| #if BOOTLOADER_SHOWLOGO
|
| case MP_BERLIN_INTR_ID(IRQ_dHubIntrAvio0):
|
| {
|
| extern void showlogo_isr();
|
| showlogo_isr();
|
| break;
|
| }
|
| #endif
|
| #ifdef EMMC_BOOT
|
| case MP_BERLIN_INTR_ID(IRQ_emmc_int):
|
| MM4_ISR(2);
|
| break;
|
| #endif
|
| default:
|
| break;
|
| }
|
|
|
|
|
| // writing ID to End of Interrupt register changes the interrupt from Active to Inactive
|
| GIC_EndInterrupt = MPCoreInterruptID;
|
| }
|
|
|
|
|
|
|