blob: 5cdbf45c01c6eeafe7393505de56e6477f43da39 [file] [log] [blame]
/********************************************************************************
* 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;
}