You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2442 lines
66 KiB
2442 lines
66 KiB
/* vxbArmGenIntCtlrV3.c - ARM generic interrupt controller driver */
|
|
|
|
/*
|
|
*
|
|
* This program is OPEN SOURCE software: you can redistribute it and/or modify it;
|
|
* This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
|
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
*
|
|
*/
|
|
|
|
#include <vxWorks.h>
|
|
#include <vsbConfig.h>
|
|
#include <intLib.h>
|
|
#include <arch/arm/intArmLib.h>
|
|
#include <arch/arm/excArmLib.h>
|
|
#include <arch/arm/vxAtomicArchLib.h>
|
|
#include <iv.h>
|
|
|
|
#include <sysLib.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <memLib.h>
|
|
|
|
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
|
# include <private/eventP.h>
|
|
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
|
#include <vxCpuLib.h>
|
|
#include <hwif/util/hwMemLib.h>
|
|
#include <vxBusLib.h>
|
|
#include <hwif/vxbus/vxBus.h>
|
|
#include <hwif/vxbus/vxbPlbLib.h>
|
|
#include <hwif/vxbus/vxbIntrCtlr.h>
|
|
#include <../src/hwif/intCtlr/vxbIntCtlrLib.h>
|
|
#include <hwif/vxbus/hwConf.h>
|
|
#include "../h/vxbus/vxbAccess.h"
|
|
#include "vxbArmGenIntCtlrV3.h"
|
|
#include "ft2000-4.h"
|
|
#ifdef _WRS_CONFIG_SMP
|
|
# include <vxIpiLib.h>
|
|
# include <private/cpcLibP.h>
|
|
#endif
|
|
|
|
/* define */
|
|
|
|
#ifdef ARMBE8
|
|
# define SWAP32 vxbSwap32
|
|
# define SWAP64(var64) ((SWAP32((var64) & 0x00000000FFFFFFFF) << 32) | \
|
|
(SWAP32(((var64) & 0xFFFFFFFF00000000) >> 32)))
|
|
#else
|
|
# define SWAP32
|
|
# define SWAP64
|
|
#endif /* ARMBE8 */
|
|
|
|
/* vxBus Driver Name */
|
|
|
|
#define GIC_NAME "armGicDev"
|
|
|
|
/* Connect the interrupt handler to it's exception vector */
|
|
|
|
#define INTR_EXC_ID (EXC_OFF_IRQ) /* exception id, for external interrupt */
|
|
|
|
#define GIC_IPI_PRIORITY 0
|
|
#define GIC_PRIORITY_LEVEL_STEP 0x10
|
|
#define GIC_SPI_PRIORITY_DEFAULT 0x10101010
|
|
|
|
#ifndef EXC_CONNECT_INTR_RTN
|
|
# define EXC_CONNECT_INTR_RTN(rtn) \
|
|
excIntConnect ((VOIDFUNCPTR *)INTR_EXC_ID,rtn)
|
|
#endif
|
|
|
|
/* This sets the CPU interrupt enable on */
|
|
|
|
#ifndef CPU_INTERRUPT_ENABLE
|
|
# define CPU_INTERRUPT_ENABLE intCpuUnlock(0)
|
|
#endif
|
|
|
|
/* This resets the CPU interrupt enable */
|
|
|
|
#ifndef CPU_INTERRUPT_DISABLE
|
|
# define CPU_INTERRUPT_DISABLE intCpuLock()
|
|
#endif
|
|
|
|
#define GIC_ISR(pEnt,inputPin,func) \
|
|
{ \
|
|
struct vxbIntCtlrPin * pPin = \
|
|
vxbIntCtlrPinEntryGet(pEnt,inputPin); \
|
|
func = pPin->isr; \
|
|
}
|
|
|
|
#define GIC_DESTCPU(pEnt,inputPin,destCpu) \
|
|
{ \
|
|
struct vxbIntCtlrPin * pPin = \
|
|
vxbIntCtlrPinEntryGet(pEnt,inputPin); \
|
|
destCpu = pPin->pinCpu; \
|
|
}
|
|
|
|
/* structure holding Generic Interupt Controller details */
|
|
|
|
typedef struct armGicDrvCtrl
|
|
{
|
|
VXB_DEVICE_ID pInst; /* instance pointer */
|
|
BOOL initialized;
|
|
struct intCtlrHwConf isrHandle;
|
|
int intMode; /* type of interrupt handling*/
|
|
void * gicBase; /* gic base address */
|
|
INT32 gicDistOffset; /* distributor register base offset */
|
|
INT32 gicReDistOffset; /* Rdistributor register base offset */
|
|
INT32 gicCpuOffset; /* CPU interface register base offset */
|
|
UINT32 gicLvlCurrent;
|
|
void * regBase;
|
|
void * handle;
|
|
INT32 gicLvlNum; /* the maximum interrupt level number */
|
|
INT32 gicCpuNum; /* the maximum CPU number in system */
|
|
} ARM_GIC_DRV_CTRL;
|
|
|
|
/* forward declarations */
|
|
|
|
IMPORT STATUS (*_func_intConnectRtn) (VOIDFUNCPTR *, VOIDFUNCPTR, int);
|
|
IMPORT STATUS (*_func_intDisconnectRtn) (VOIDFUNCPTR *, VOIDFUNCPTR, int);
|
|
IMPORT UINT32 vxCpuIdGetByIndex(UINT32 idx);
|
|
LOCAL STATUS vxbArmGicDevInit (VXB_DEVICE_ID pInst);
|
|
#ifdef _WRS_CONFIG_SMP
|
|
STATUS vxbArmGicLvlVecChk (VXB_DEVICE_ID pInst, int*, int*, int*);
|
|
STATUS vxbArmGicLvlVecAck (VXB_DEVICE_ID pInst, int, int, int);
|
|
#else
|
|
STATUS vxbArmGicLvlVecChk (VXB_DEVICE_ID pInst, int*, int*);
|
|
STATUS vxbArmGicLvlVecAck (VXB_DEVICE_ID pInst, int, int);
|
|
#endif
|
|
int vxbArmGicLvlChg (VXB_DEVICE_ID pInst, int);
|
|
LOCAL STATUS vxbArmGicIntDevInit (int cpuNum);
|
|
#ifdef INCLUDE_SHOW_ROUTINES
|
|
void vxbArmGicDataShow (VXB_DEVICE_ID pInst, int *dummy);
|
|
#endif /* INCLUDE_SHOW_ROUTINES */
|
|
|
|
LOCAL void vxbArmGicCtlInit(VXB_DEVICE_ID pInst);
|
|
LOCAL void vxbArmGicCtlInit2(VXB_DEVICE_ID pInst);
|
|
LOCAL STATUS sysArmGicConnect
|
|
(
|
|
VOIDFUNCPTR * vector, /* interrupt vector to attach to */
|
|
VOIDFUNCPTR routine, /* routine to be called */
|
|
int parameter /* parameter to be passed to routine */
|
|
);
|
|
LOCAL STATUS sysArmGicDisconnect
|
|
(
|
|
VOIDFUNCPTR * vector, /* interrupt vector to detach from */
|
|
VOIDFUNCPTR routine, /* routine to be disconnected */
|
|
int parameter /* parameter to be matched */
|
|
);
|
|
LOCAL STATUS sysArmGicISREnable
|
|
(
|
|
struct intCtlrHwConf * pEntries,
|
|
int inputPin
|
|
);
|
|
LOCAL STATUS sysArmGicEnable
|
|
(
|
|
int vector
|
|
);
|
|
LOCAL STATUS sysArmGicISRDisable
|
|
(
|
|
struct intCtlrHwConf * pEntries,
|
|
int inputPin
|
|
);
|
|
LOCAL STATUS sysArmGicDisable
|
|
(
|
|
int vector
|
|
);
|
|
LOCAL STATUS vxbArmGicConnect
|
|
(
|
|
VXB_DEVICE_ID pIntCtlr, /* int Ctlr device struct */
|
|
VXB_DEVICE_ID pDev, /* device being connnected */
|
|
int index, /* device index */
|
|
void (*pIsr)(void * pArg), /* isr being connected */
|
|
void * pArg, /* isr's arg */
|
|
int * pInputPin /* input pin device is on */
|
|
);
|
|
LOCAL STATUS vxbArmGicDisconnect
|
|
(
|
|
VXB_DEVICE_ID pIntCtlr, /* int Ctlr device struct */
|
|
VXB_DEVICE_ID pDev, /* device being connnected */
|
|
int index, /* device index */
|
|
VOIDFUNCPTR pIsr, /* isr being connected */
|
|
void * pArg /* isr's arg */
|
|
);
|
|
LOCAL STATUS vxbArmGicEnable
|
|
(
|
|
VXB_DEVICE_ID pIntCtlr, /* int Ctlr device struct */
|
|
VXB_DEVICE_ID pDev, /* device being connnected */
|
|
int index, /* device index */
|
|
VOIDFUNCPTR pIsr, /* isr being connected */
|
|
void * pArg /* isr's arg */
|
|
);
|
|
LOCAL STATUS vxbArmGicDisable
|
|
(
|
|
VXB_DEVICE_ID pIntCtlr, /* int Ctlr device struct */
|
|
VXB_DEVICE_ID pDev, /* device being connnected */
|
|
int index, /* device index */
|
|
VOIDFUNCPTR pIsr, /* isr being connected */
|
|
void * pArg /* isr's arg */
|
|
);
|
|
LOCAL STATUS vxbArmGicLvlEnable(VXB_DEVICE_ID pInst, int level);
|
|
LOCAL STATUS vxbArmGicLvlDisable(VXB_DEVICE_ID pInst, int level);
|
|
LOCAL int vxbArmGicHwLvlChg(int level);
|
|
|
|
#ifdef _WRS_CONFIG_SMP
|
|
LOCAL STATUS vxbArmGicHwEnable(int inputPin);
|
|
LOCAL STATUS vxbArmGicHwDisable(int inputPin);
|
|
void sysArmGicDevInit(void);
|
|
LOCAL STATUS vxbArmGicIpiGen(VXB_DEVICE_ID pCtlr, INT32 ipiId,
|
|
cpuset_t cpus);
|
|
LOCAL STATUS vxbArmGicIpiConnect(VXB_DEVICE_ID pCtlr, INT32 ipiId, \
|
|
IPI_HANDLER_FUNC ipiHandler, void * ipiArg);
|
|
LOCAL STATUS vxbArmGicIpiDisconnect(VXB_DEVICE_ID pCtlr, INT32 ipiId, \
|
|
IPI_HANDLER_FUNC ipiHandler, void * ipiArg);
|
|
LOCAL STATUS vxbArmGicIpiEnable(VXB_DEVICE_ID pCtlr, INT32 ipiId);
|
|
LOCAL STATUS vxbArmGicIpiDisable(VXB_DEVICE_ID pCtlr, INT32 ipiId);
|
|
LOCAL INT32 vxbArmGicIpiPrioGet(VXB_DEVICE_ID pCtlr, INT32 ipiId);
|
|
LOCAL STATUS vxbArmGicIpiPrioSet(VXB_DEVICE_ID pCtlr, INT32 ipiId, \
|
|
INT32 prio);
|
|
LOCAL VXIPI_CTRL_INIT * vxbArmGicIpiCtlGet(VXB_DEVICE_ID pInst, \
|
|
void * pArg);
|
|
LOCAL STATUS vxbArmGicIntReroute(VXB_DEVICE_ID pDev, int index, \
|
|
cpuset_t destCpu);
|
|
LOCAL STATUS vxbArmGicCpuReroute(VXB_DEVICE_ID pDev,void * destCpu);
|
|
|
|
METHOD_DECL(vxbArmGicIntCtlInit);
|
|
DEVMETHOD_DEF(vxbArmGicIntCtlInit, "Init ARM general interrupt controller");
|
|
#endif /* _WRS_CONFIG_SMP */
|
|
|
|
/* GIC base address */
|
|
|
|
LOCAL UINT32 armGicBase = 0;
|
|
|
|
/*
|
|
* Distributor and CPU interface register base offsets,
|
|
* with backward-compatible default values for ARM11 MPCore and Cortex-A9 cores.
|
|
*/
|
|
|
|
LOCAL UINT32 armGicDistOffset = 0x1000;
|
|
LOCAL UINT32 armGicReDistOffset = 0x1000;
|
|
LOCAL UINT32 armGicCpuOffset = 0x100;
|
|
LOCAL UINT32 gicVersion = GIC_VERSION_GIC400;
|
|
|
|
/* armGicLinesNum is used to reduce interrupt process time */
|
|
|
|
LOCAL UINT32 armGicLinesNum = 0;
|
|
|
|
/* GIC priority levels */
|
|
|
|
LOCAL UINT32 armGicPriorityLvlMax = 0;
|
|
|
|
LOCAL VXB_DEVICE_ID vxbGicId; /* GIC device ID */
|
|
LOCAL ARM_GIC_DRV_CTRL * pVxbArmGicDrvCtrl = NULL;
|
|
|
|
LOCAL struct drvBusFuncs vxbArmGicCtlFuncs =
|
|
{
|
|
vxbArmGicCtlInit, /* devInstanceInit */
|
|
vxbArmGicCtlInit2, /* devInstanceInit2 */
|
|
NULL /* devConnect */
|
|
};
|
|
|
|
/* vxBus vxbArmGicCtl driver registration data structure */
|
|
|
|
LOCAL struct vxbDevRegInfo armGicCtlRegistration =
|
|
{
|
|
NULL, /* pNext */
|
|
VXB_DEVID_DEVICE, /* devID */
|
|
VXB_BUSID_PLB, /* busID = PLB */
|
|
VXB_VER_4_0_0, /* vxbVersion */
|
|
GIC_NAME, /* drvName */
|
|
&vxbArmGicCtlFuncs, /* pDrvBusFuncs */
|
|
NULL, /* pMethods */
|
|
NULL, /* devProbe */
|
|
NULL /* pParamDefaults */
|
|
};
|
|
|
|
LOCAL device_method_t gicIntCtlr_methods[] =
|
|
{
|
|
DEVMETHOD(vxbIntCtlrConnect, vxbArmGicConnect),
|
|
DEVMETHOD(vxbIntCtlrDisconnect, vxbArmGicDisconnect),
|
|
DEVMETHOD(vxbIntCtlrEnable, vxbArmGicEnable),
|
|
DEVMETHOD(vxbIntCtlrDisable, vxbArmGicDisable),
|
|
|
|
#ifdef _WRS_CONFIG_SMP
|
|
DEVMETHOD(vxIpiControlGet, vxbArmGicIpiCtlGet),
|
|
DEVMETHOD(vxbIntCtlrIntReroute, vxbArmGicIntReroute),
|
|
DEVMETHOD(vxbIntCtlrCpuReroute, vxbArmGicCpuReroute),
|
|
#endif /* _WRS_CONFIG_SMP */
|
|
|
|
#ifdef GIC_INTCTLR_DEBUG_ON
|
|
DEVMETHOD(busDevShow, vxbArmGicShow),
|
|
#endif /* GIC_INTCTLR_DEBUG_ON */
|
|
|
|
{ 0, 0}
|
|
};
|
|
|
|
#ifdef _WRS_CONFIG_SMP
|
|
IMPORT UINT32 vxCpuIndexGet(void);
|
|
|
|
/*
|
|
* This structure is initialized with the control functions for the IPI
|
|
* interface. This set of functions allow the CPC layer to manipulate IPI
|
|
* interrupts.
|
|
*/
|
|
|
|
LOCAL VXIPI_CTRL_INIT_DECL (vxArmGicIpiCtrlInit,
|
|
{NULL}, /* ipiList */
|
|
0, /* pCpus */
|
|
vxbArmGicIpiGen, /* ipiEmitFunc */
|
|
vxbArmGicIpiConnect, /* ipiConnectFunc */
|
|
vxbArmGicIpiEnable, /* ipiEnableFunc */
|
|
vxbArmGicIpiDisable, /* ipiDisableFunc */
|
|
vxbArmGicIpiDisconnect, /* ipiDisconnFunc */
|
|
vxbArmGicIpiPrioGet, /* ipiPrioGetFunc */
|
|
vxbArmGicIpiPrioSet, /* ipiPrioSetFunc */
|
|
ARM_GIC_IPI_COUNT, /* ipiCount */
|
|
NULL /* pCtlr */
|
|
);
|
|
#endif /* _WRS_CONFIG_SMP */
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbArmGicNonPreempISR - non-pre-emptive interrupt exception handler
|
|
*
|
|
* This handler does not provide pre-emptive interrupts. If a high
|
|
* priority interrupt occurs while a low priority interrupt is being
|
|
* handled, the high priority interrupt must wait for the low priority
|
|
* interrupt handler to finish. As soon as the low-priority handler is
|
|
* done, the high priority handler will be invoked. This model has less
|
|
* exception handling overhead of the fully pre-emptive model, but has a
|
|
* greater worst case latency for high priority interrupts.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERROR: N/A
|
|
*/
|
|
|
|
LOCAL void vxbArmGicNonPreempISR ()
|
|
{
|
|
int level;
|
|
int vector;
|
|
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
|
int loopCnt = -1;
|
|
#endif
|
|
#ifdef _WRS_CONFIG_SMP
|
|
int srcCpuId = 0;
|
|
#endif
|
|
|
|
#ifdef _WRS_CONFIG_SMP
|
|
if (vxbArmGicLvlVecChk (pVxbArmGicDrvCtrl->pInst, &level, &vector,
|
|
&srcCpuId) == ERROR)
|
|
#else
|
|
if (vxbArmGicLvlVecChk (pVxbArmGicDrvCtrl->pInst, &level, &vector) == ERROR)
|
|
#endif
|
|
{
|
|
return;
|
|
}
|
|
|
|
do
|
|
{
|
|
|
|
/* Loop until no more interrupts are found */
|
|
|
|
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
|
|
|
/*
|
|
* In the ARM architecture, exceptions cannot be locked out
|
|
* with intCpuLock() which makes a two-stage logging approach (i.e.
|
|
* timestamp saved in intEnt and then used here) dangerous...it
|
|
* can lead to out-of sequence events in the event log, thus
|
|
* confusing the parser. So we just use a single stage logging
|
|
* here.
|
|
*/
|
|
|
|
WV_EVT_INT_ENT (vector)
|
|
loopCnt++;
|
|
|
|
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
|
|
|
VXB_INTCTLR_ISR_CALL (&(pVxbArmGicDrvCtrl->isrHandle), vector)
|
|
|
|
/* acknowledge the interrupt and restore interrupt level */
|
|
|
|
#ifdef _WRS_CONFIG_SMP
|
|
vxbArmGicLvlVecAck (pVxbArmGicDrvCtrl->pInst, level, vector, srcCpuId);
|
|
#else
|
|
vxbArmGicLvlVecAck (pVxbArmGicDrvCtrl->pInst, level, vector);
|
|
#endif
|
|
}
|
|
#ifdef _WRS_CONFIG_SMP
|
|
while (vxbArmGicLvlVecChk (pVxbArmGicDrvCtrl->pInst, &level, &vector,
|
|
&srcCpuId) != ERROR);
|
|
#else
|
|
while (vxbArmGicLvlVecChk (pVxbArmGicDrvCtrl->pInst, &level, &vector)
|
|
!= ERROR);
|
|
#endif
|
|
|
|
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
|
while (loopCnt-- > 0)
|
|
EVT_CTX_0(EVENT_INT_EXIT);
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbArmGicPreempISR - pre-emptive interrupt exception handler
|
|
*
|
|
* This handler is fully pre-emptive. In this model, high priority
|
|
* interrupts are enabled during the processing of low-priority
|
|
* interrupts. Should a high priority interrupt occur, the low-priority
|
|
* handler is interrupted and the high priority handler takes over.
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL void vxbArmGicPreempISR()
|
|
{
|
|
int vector, level;
|
|
#ifdef _WRS_CONFIG_SMP
|
|
int srcCpuId = 0;
|
|
#endif
|
|
|
|
#ifdef _WRS_CONFIG_SMP
|
|
if (vxbArmGicLvlVecChk (pVxbArmGicDrvCtrl->pInst, &level, &vector,
|
|
&srcCpuId) == ERROR)
|
|
#else
|
|
if (vxbArmGicLvlVecChk (pVxbArmGicDrvCtrl->pInst, &level, &vector) == ERROR)
|
|
#endif
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
|
|
|
/*
|
|
* In the ARM architecture, exceptions cannot be locked out with intCpuLock()
|
|
* which makes a two-stage logging approach (i.e. timestamp saved in intEnt
|
|
* and then used here) dangerous...it can lead to out-of sequence events
|
|
* in the event log, thus confusing the parser. So we just use a single
|
|
* stage logging here
|
|
*/
|
|
|
|
WV_EVT_INT_ENT(vector)
|
|
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
|
|
|
CPU_INTERRUPT_ENABLE;
|
|
|
|
VXB_INTCTLR_ISR_CALL (&(pVxbArmGicDrvCtrl->isrHandle), vector)
|
|
|
|
CPU_INTERRUPT_DISABLE;
|
|
|
|
/* acknowledge the interrupt and restore interrupt level */
|
|
|
|
#ifdef _WRS_CONFIG_SMP
|
|
vxbArmGicLvlVecAck (pVxbArmGicDrvCtrl->pInst, level, vector, srcCpuId);
|
|
#else
|
|
vxbArmGicLvlVecAck (pVxbArmGicDrvCtrl->pInst, level, vector);
|
|
#endif /* _WRS_CONFIG_SMP */
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbFTIntCtlrRegister - register GIC driver
|
|
*
|
|
* This routine registers the GIC driver with vxbus as a child
|
|
* of the PLB bus type.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
void vxbFTIntCtlrRegister(void)
|
|
{
|
|
vxbDevRegister ((struct vxbDevRegInfo *)&armGicCtlRegistration);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbArmGenIntCtlrInit - initialize the device
|
|
*
|
|
* This is the vxbArmGenIntrClt initialization routine. It retrieves and stores
|
|
* device driver control data, connects the device driver specific routines into
|
|
* the architecture level hooks and initializes the interrupt controller.
|
|
* If the BSP needs to create a wrapper routine around any of the architecture
|
|
* level routines, it should install the pointer to the wrapper routine after
|
|
* calling this routine.
|
|
*
|
|
* NOTE:
|
|
*
|
|
* This routine is called early during system initialization (sysHwInit), and
|
|
* *MUST NOT* make calls to OS facilities such as memory allocation
|
|
* and I/O. It is called from the vxBus routine hardWareInterFaceInit();
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO
|
|
*/
|
|
|
|
LOCAL void vxbArmGicCtlInit
|
|
(
|
|
VXB_DEVICE_ID pInst
|
|
)
|
|
{
|
|
ARM_GIC_DRV_CTRL * pDrvCtrl;
|
|
HCF_DEVICE * pHcf;
|
|
|
|
/* get the HCF device from the instance ID */
|
|
|
|
pHcf = hcfDeviceGet (pInst);
|
|
|
|
/* if pHcf is NULL, no device is present in hwconf.c */
|
|
|
|
if (pHcf == NULL)
|
|
return;
|
|
|
|
/* allocate memory for the data */
|
|
|
|
pDrvCtrl = (ARM_GIC_DRV_CTRL *)hwMemAlloc (sizeof(ARM_GIC_DRV_CTRL));
|
|
|
|
if (pDrvCtrl == NULL)
|
|
return;
|
|
|
|
pDrvCtrl->pInst = pInst;
|
|
|
|
vxbGicId = pInst;
|
|
|
|
/* update the driver control data pointer */
|
|
|
|
pInst->pDrvCtrl = pDrvCtrl;
|
|
|
|
pVxbArmGicDrvCtrl = pDrvCtrl;
|
|
|
|
/* get connectivity info from hwconf */
|
|
|
|
intCtlrHwConfGet (pInst, pHcf, &(pDrvCtrl->isrHandle));
|
|
|
|
/*
|
|
* resourceDesc {
|
|
* The intMode resource specifies the interrupt mode. Interrupts can be in
|
|
* either preemptive or non-preemptive mode, and the associated macro
|
|
* definition is INT_PREEMPT_MODEL or INT_NON_PREEMPT_MODEL.
|
|
*
|
|
* The maxIntLvl resource specifies the number of interrupt level.
|
|
*
|
|
* The maxCpuNum resource specifies the number of CPU. It is 1 for uni-core
|
|
* system. It may be 2, 3 or 4 for multi-core system.
|
|
}
|
|
*/
|
|
|
|
if (devResourceGet (pHcf, "intMode", HCF_RES_INT,
|
|
(void *)&pDrvCtrl->intMode) != OK)
|
|
{
|
|
#ifndef _VXBUS_BASIC_HWMEMLIB
|
|
hwMemFree((char *)pDrvCtrl);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
pDrvCtrl->gicBase = pInst->pRegBase[0];
|
|
armGicBase = (UINT32)pDrvCtrl->gicBase;
|
|
|
|
vxbRegMap(pInst, 0, &pDrvCtrl->handle);
|
|
|
|
/*
|
|
* Get the distributor and CPU interface register base addresses,
|
|
* using the default (for backward-compatibility with ARM11 MPCore and
|
|
* Cortex-A9) if they're not supplied by the BSP.
|
|
*/
|
|
|
|
if (devResourceGet (pHcf, "distOffset", HCF_RES_INT,
|
|
(void *)&pDrvCtrl->gicDistOffset) != OK)
|
|
{
|
|
|
|
/* not found, so use default */
|
|
|
|
pDrvCtrl->gicDistOffset = armGicDistOffset;
|
|
}
|
|
else
|
|
armGicDistOffset = pDrvCtrl->gicDistOffset;
|
|
|
|
|
|
if (devResourceGet (pHcf, "redistOffset", HCF_RES_INT,
|
|
(void *)&pDrvCtrl->gicReDistOffset) != OK)
|
|
{
|
|
|
|
/* not found, so use default */
|
|
|
|
pDrvCtrl->gicReDistOffset = armGicReDistOffset;
|
|
}
|
|
else
|
|
armGicReDistOffset = pDrvCtrl->gicReDistOffset;
|
|
|
|
if (devResourceGet (pHcf, "cpuOffset", HCF_RES_INT,
|
|
(void *)&pDrvCtrl->gicCpuOffset) != OK)
|
|
{
|
|
|
|
/* not found, so use default */
|
|
|
|
pDrvCtrl->gicCpuOffset = armGicCpuOffset;
|
|
}
|
|
else
|
|
armGicCpuOffset = pDrvCtrl->gicCpuOffset;
|
|
|
|
/* get the maximum interrupt level number from hardware register */
|
|
|
|
pDrvCtrl->gicLvlNum = ((SWAP32 (*GIC_Type) & 0x1f) + 1) * 32;
|
|
|
|
armGicLinesNum = pDrvCtrl->gicLvlNum;
|
|
if (armGicLinesNum > GIC_INT_MAX_NUM)
|
|
{
|
|
#ifndef _VXBUS_BASIC_HWMEMLIB
|
|
hwMemFree((char *)pDrvCtrl);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
#ifdef _WRS_CONFIG_SMP
|
|
|
|
/* get the maximum CPU numbers */
|
|
|
|
if (devResourceGet (pHcf, "maxCpuNum", HCF_RES_INT,
|
|
(void *)&pDrvCtrl->gicCpuNum) != OK)
|
|
{
|
|
#ifndef _VXBUS_BASIC_HWMEMLIB
|
|
hwMemFree((char *)pDrvCtrl);
|
|
#endif
|
|
return;
|
|
}
|
|
#else
|
|
pDrvCtrl->gicCpuNum = 1;
|
|
#endif /* _WRS_CONFIG_SMP */
|
|
|
|
pInst->pMethods = &gicIntCtlr_methods[0];
|
|
|
|
/* Install three pointers for legacy type intEnable/intDisable/intLevelSet */
|
|
|
|
sysIntLvlEnableRtn = (FUNCPTR)sysArmGicEnable;
|
|
sysIntLvlDisableRtn = (FUNCPTR)sysArmGicDisable;
|
|
sysIntLvlChgRtn = (FUNCPTR)vxbArmGicHwLvlChg;
|
|
|
|
if (_func_intConnectRtn == NULL)
|
|
_func_intConnectRtn = sysArmGicConnect;
|
|
|
|
if (_func_intDisconnectRtn == NULL)
|
|
_func_intDisconnectRtn = sysArmGicDisconnect;
|
|
|
|
/* initialize the GIC */
|
|
|
|
vxbArmGicDevInit (pInst);
|
|
|
|
/* assign ISR to hook (defined in excArchLib.c) */
|
|
|
|
if (pDrvCtrl->intMode & INT_PREEMPT_MODEL)
|
|
EXC_CONNECT_INTR_RTN (vxbArmGicPreempISR);
|
|
else
|
|
EXC_CONNECT_INTR_RTN (vxbArmGicNonPreempISR);
|
|
|
|
/*arm_gicv3_init(0);*/
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbArmGenIntCtlrInit2 - second level initialization of the ARM GIC
|
|
*
|
|
* This is the second level ARM GIC initialization routine. Nothing needs to
|
|
* be done during this level of initialization.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO
|
|
*/
|
|
|
|
LOCAL void vxbArmGicCtlInit2
|
|
(
|
|
VXB_DEVICE_ID pInst
|
|
)
|
|
{
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbArmGicDevInit - initialize the interrupt controller
|
|
*
|
|
* This routine initializes the interrupt controller device, disabling all
|
|
* interrupt sources. It connects the device driver specific routines
|
|
* into the architecture level hooks. If the BSP needs to create a wrapper
|
|
* routine around any of the architecture level routines, it should install the
|
|
* pointer to the wrapper routine after calling this routine.
|
|
*
|
|
* RETURNS: OK or ERROR if parameter is invalid.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS vxbArmGicDevInit
|
|
(
|
|
VXB_DEVICE_ID pInst
|
|
)
|
|
{
|
|
|
|
ARM_GIC_DRV_CTRL * pDrvCtrl;
|
|
|
|
/* if parameters are invalid, return ERROR */
|
|
|
|
if ((pInst == NULL) || (pInst->pDrvCtrl == NULL))
|
|
return (ERROR);
|
|
|
|
/* retrieve the data */
|
|
|
|
pDrvCtrl = (ARM_GIC_DRV_CTRL *)(pInst->pDrvCtrl);
|
|
|
|
pDrvCtrl->gicLvlCurrent = GIC_INT_ALL_ENABLED;
|
|
|
|
vxbArmGicIntDevInit(0);
|
|
|
|
vxbArmGicLvlChg (pInst, GIC_INT_ALL_ENABLED); /* enable all levels */
|
|
|
|
return OK;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbArmGicIntDevInit - initialize the interrupt controller
|
|
*
|
|
* This routine initializes the interrupt controller device, disabling all
|
|
* interrupt sources. It connects the device driver specific routines into the
|
|
* architecture level hooks. If the BSP needs to create a wrapper routine
|
|
* around any of the architecture level routines, it should install the pointer
|
|
* to the wrapper routine after calling this routine.
|
|
*
|
|
* Note that for multicore processor, some registers are banked for each process.
|
|
* This routine uses CPU0 to initialize the common resources and banked
|
|
* registers are processed by every processor.
|
|
*
|
|
* RETURNS: always OK
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS vxbArmGicIntDevInit
|
|
(
|
|
int cpuNum
|
|
)
|
|
{
|
|
int i;
|
|
UINT32 aGicPrio = 0;
|
|
UINT32 aGicCfg = 0;
|
|
STATUS stat;
|
|
HCF_DEVICE * pHcf;
|
|
struct intrCtlrPriority * pPrioTable;
|
|
struct intrCtlrTrigger * pTrigTable = NULL;
|
|
int tableSize;
|
|
void * pValue;
|
|
UINT32 val;
|
|
UINT32 count = 1000; /* 1s! */
|
|
INT32 regGicLineNum;
|
|
#ifndef _WRS_CONFIG_WRHV_GUEST
|
|
|
|
pHcf = hcfDeviceGet (vxbGicId);
|
|
if (pHcf == NULL)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
val = *GICR_WAKER_CPU(cpuNum);
|
|
/* Wake up this CPU redistributor */
|
|
#define GICR_WAKER_ProcessorSleep (1U << 1)
|
|
#define GICR_WAKER_ChildrenAsleep (1U << 2)
|
|
val &= ~GICR_WAKER_ProcessorSleep;
|
|
*GICR_WAKER_CPU(cpuNum) = val;
|
|
|
|
while (--count) {
|
|
val = *GICR_WAKER_CPU(cpuNum);
|
|
if (1 ^ (val & GICR_WAKER_ChildrenAsleep))
|
|
break;
|
|
|
|
};
|
|
/* disable distributor */
|
|
|
|
val = *GICR_IntEnable;
|
|
*GICR_IntEnClr_CPU(cpuNum) = SWAP32 (ALL_PPI_INT_MASK);
|
|
*GICR_IntEnable_CPU(cpuNum) = ALL_SGI_INT_MASK;
|
|
|
|
if (cpuNum == 0 &&gicVersion < GIC_VERSION_GIC400) /* CPU0 */
|
|
{
|
|
*GIC_Control = 0;
|
|
}
|
|
|
|
/* disable this processor's CPU interface */
|
|
#ifdef SUPPORT_GICC
|
|
*GIC_CPU_Control = 0;
|
|
#else
|
|
|
|
sys_icc_pmr_set(0xf0);
|
|
|
|
sys_icc_ctlr_set(0);
|
|
sys_icc_igrpen1_set(1);
|
|
|
|
if((sys_icc_igrpen1_get() & 1) != 1)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
|
|
#endif
|
|
regGicLineNum = (INT32)(SWAP32 (*GIC_Type) & 0x1f);
|
|
regGicLineNum = (regGicLineNum + 1) * 32;
|
|
|
|
|
|
|
|
/* disable all PPI interrupts */
|
|
if(cpuNum == 0 && gicVersion >= GIC_VERSION_GIC400)
|
|
{
|
|
/*
|
|
The Distributor control register (GICD_CTLR) must be configured to enable the interrupt groups and to set the routing mode.
|
|
Enable Affinity routing (ARE bits) The ARE bits in GICD_CTLR control whether affinity routing is enabled. If affinity routing is not enabled, GICv3 can be configured for legacy operation . Whether affinity routing is enabled or not can be controlled separately for Secure and Non-secure state.
|
|
Enables GICD_CTLR contains separate enable bits for Group 0, Secure Group 1 and Non-secure Group 1:
|
|
GICD_CTLR.EnableGrp1S enables distribution of Secure Group 1 interrupts.
|
|
GICD_CTLR.EnableGrp1NS enables distribution of Non-secure Group 1 interrupts.
|
|
GICD_CTLR.EnableGrp0 enables distribution of Group 0 interrupts.
|
|
*/
|
|
|
|
*GIC_Control = 0x37;
|
|
*GICR_IntEnClr = SWAP32 (ALL_PPI_INT_MASK);
|
|
*GICR_IntEnable = ALL_SGI_INT_MASK;
|
|
|
|
/* *GICR_IGROUPR0 = SWAP32(0x0000ffff);*/
|
|
}
|
|
else if (gicVersion <GIC_VERSION_GIC400)
|
|
{
|
|
*GIC_IntEnClr(0) = SWAP32 (ALL_PPI_INT_MASK);
|
|
}
|
|
|
|
/* Get the max priority */
|
|
|
|
*GIC_Prio(SPI_START_INT_NUM) = SWAP32 (0xff);
|
|
armGicPriorityLvlMax = SWAP32 (*GIC_Prio(SPI_START_INT_NUM));
|
|
*GIC_Prio(SPI_START_INT_NUM) = 0;
|
|
|
|
/* clear all pending PPI and SGI interrupts in the distributor */
|
|
/* req: VX7-16231 */
|
|
if( gicVersion >= GIC_VERSION_GIC400)
|
|
{
|
|
*GICR_IntPendClr = SWAP32 (ALL_PPI_INT_MASK | ALL_SGI_INT_MASK);
|
|
}
|
|
else
|
|
{
|
|
*GIC_IntPendClr(0) = SWAP32 (ALL_PPI_INT_MASK | ALL_SGI_INT_MASK);
|
|
}
|
|
|
|
/* set default priority for all PPI and SGI interrupts to level 0(highest) */
|
|
|
|
for (i = 0; i < SPI_START_INT_NUM; i += PRIOS_PER_WORD)
|
|
*GICR_Prio_CPU(cpuNum,i) = GIC_IPI_PRIORITY;
|
|
|
|
if (cpuNum == 0) /* CPU0 */
|
|
{
|
|
|
|
/*
|
|
* Disable all SPI interrupts
|
|
* Clear all pending SPI interrupts in the distributor
|
|
*/
|
|
|
|
for(i = SPI_START_INT_NUM; i < GIC_INT_MAX_NUM; i += BITS_PER_WORD)
|
|
{
|
|
*GIC_IntEnClr(i) = SWAP32 (0xffffffff);
|
|
*GIC_IntPendClr(i) = SWAP32 (0xffffffff);
|
|
}
|
|
|
|
/*
|
|
* set default priority for all SPI interrupts to level 0 and direct all
|
|
* interrupts to go to CPU 0
|
|
*/
|
|
|
|
for (i = SPI_START_INT_NUM; i < armGicLinesNum; /*i += PRIOS_PER_WORD*/)
|
|
{
|
|
*GIC_Prio(i) = GIC_SPI_PRIORITY_DEFAULT;
|
|
if(gicVersion < GIC_VERSION_GIC400)
|
|
{
|
|
|
|
*GIC_CPUTarg(i) = SWAP32 ( GIC_CPU_DIR_DEFAULT );
|
|
i += 4;
|
|
}
|
|
else
|
|
{
|
|
*GIC_IntRpute(i) = (UINT64)SWAP64 (GIC_V3_CPU_DIR_DEFAULT);
|
|
i ++;
|
|
}
|
|
}
|
|
|
|
/* setting whether 1-N/N-N and Level/Edge triggered */
|
|
|
|
for (i = SPI_START_INT_NUM; i < armGicLinesNum; i += CONFIGS_PER_WORD)
|
|
{
|
|
*GIC_Config(i) = SWAP32 ( GIC_INT_ONEMINUS_HIGH ); /* 1-N, Level */
|
|
}
|
|
|
|
/*
|
|
* get trigger table from hwconf
|
|
*
|
|
* resourceDesc {
|
|
* The trigger resource specifies a pointer to a
|
|
* intrCtlrTrigger structure which configures triggering
|
|
* for particular interrupt vectors. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "trigger", HCF_RES_ADDR, &pValue);
|
|
pTrigTable = (struct intrCtlrTrigger *)pValue;
|
|
if (stat == OK)
|
|
{
|
|
stat = devResourceGet(pHcf, "triggerTableSize", HCF_RES_INT,
|
|
(void *) &tableSize);
|
|
if (stat == OK)
|
|
{
|
|
for ( i = 0 ; i < tableSize ; i++ )
|
|
{
|
|
if (pTrigTable->inputPin > armGicLinesNum)
|
|
{
|
|
pTrigTable++;
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* The GIC does not permit use of the Interrupt
|
|
* Configuration Register to program the trigger
|
|
* mode of PPIs.
|
|
*/
|
|
|
|
if (pTrigTable->inputPin >= SPI_START_INT_NUM)
|
|
{
|
|
aGicCfg = SWAP32 (*GIC_Config(pTrigTable->inputPin));
|
|
|
|
/*
|
|
* Trigger configure type:
|
|
*
|
|
* VXB_INTR_TRIG_FALLING_EDGE == edge triggered,
|
|
* falling edge
|
|
* VXB_INTR_TRIG_RISING_EDGE == edge triggered,
|
|
* rising edge
|
|
* VXB_INTR_TRIG_ACTIVE_LOW == level sensitive,
|
|
* active low
|
|
* VXB_INTR_TRIG_ACTIVE_HIGH == level sensitive,
|
|
* active high
|
|
*/
|
|
|
|
if (pTrigTable->trigger & VXB_INTR_TRIG_LEVEL)
|
|
{
|
|
aGicCfg &=
|
|
~(BIT (((pTrigTable->inputPin % CONFIGS_PER_WORD)
|
|
* GIC_INT_TRIGGER_SHIFT + 1)));
|
|
}
|
|
else if (pTrigTable->trigger & VXB_INTR_TRIG_EDGE)
|
|
{
|
|
aGicCfg |=
|
|
BIT (((pTrigTable->inputPin % CONFIGS_PER_WORD)
|
|
* GIC_INT_TRIGGER_SHIFT + 1));
|
|
}
|
|
*GIC_Config(pTrigTable->inputPin) = SWAP32 (aGicCfg);
|
|
}
|
|
pTrigTable++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* get priority table from hwconf
|
|
*
|
|
* resourceDesc {
|
|
* The priority resource specifies a pointer to a
|
|
* intrCtlrPriority structure which assigns priority
|
|
* levels to particular interrupt vectors. }
|
|
*/
|
|
|
|
stat = devResourceGet(pHcf, "priority", HCF_RES_ADDR, &pValue);
|
|
pPrioTable = (struct intrCtlrPriority *)pValue;
|
|
if (stat == OK)
|
|
{
|
|
stat = devResourceGet(pHcf, "priorityTableSize", HCF_RES_INT,
|
|
(void *) &tableSize);
|
|
if (stat == OK)
|
|
{
|
|
for ( i = 0 ; i < tableSize ; i++ )
|
|
{
|
|
|
|
/* use CPU0 to set the common SPI priority */
|
|
|
|
if ((pPrioTable->inputPin >= SPI_START_INT_NUM) &&
|
|
(cpuNum != 0))
|
|
{
|
|
pPrioTable++;
|
|
continue;
|
|
}
|
|
|
|
if((gicVersion >= GIC_VERSION_GIC400) && (pPrioTable->inputPin < SPI_START_INT_NUM))
|
|
{
|
|
aGicPrio = SWAP32 (*GICR_Prio_CPU(cpuNum,pPrioTable->inputPin));
|
|
}
|
|
else
|
|
{
|
|
aGicPrio = SWAP32 (*GIC_Prio(pPrioTable->inputPin));
|
|
}
|
|
|
|
/*
|
|
* Priority range:
|
|
*
|
|
* 0x0 == GIC_INT_HIGHEST_PRIORITY, the highest priority
|
|
* 0xFF == GIC_INT_LOWEST_PRIORITY, the lowest priority
|
|
*/
|
|
|
|
if (pPrioTable->priority > armGicPriorityLvlMax)
|
|
{
|
|
aGicPrio |=
|
|
((armGicPriorityLvlMax & GIC_INT_PRIORITY_MASK)
|
|
<< ((pPrioTable->inputPin % PRIOS_PER_WORD)
|
|
* GIC_INT_PRIORITY_SHIFT));
|
|
}
|
|
else if ((pPrioTable->inputPin >= SPI_START_INT_NUM) &&
|
|
(pPrioTable->inputPin <= armGicLinesNum) &&
|
|
(pPrioTable->priority < GIC_PRIORITY_LEVEL_STEP))
|
|
{
|
|
aGicPrio |=
|
|
((GIC_PRIORITY_LEVEL_STEP & GIC_INT_PRIORITY_MASK)
|
|
<< ((pPrioTable->inputPin % PRIOS_PER_WORD)
|
|
* GIC_INT_PRIORITY_SHIFT));
|
|
}
|
|
else
|
|
{
|
|
aGicPrio |=
|
|
((pPrioTable->priority & GIC_INT_PRIORITY_MASK)
|
|
<< ((pPrioTable->inputPin % PRIOS_PER_WORD)
|
|
* GIC_INT_PRIORITY_SHIFT));
|
|
}
|
|
|
|
if((gicVersion >= GIC_VERSION_GIC400) && (pPrioTable->inputPin < SPI_START_INT_NUM))
|
|
{
|
|
*GICR_Prio_CPU(cpuNum,pPrioTable->inputPin) = SWAP32 (aGicPrio);
|
|
}
|
|
else
|
|
{
|
|
*GIC_Prio(pPrioTable->inputPin) = SWAP32 (aGicPrio);
|
|
}
|
|
|
|
pPrioTable++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* enable all interrupt priorities */
|
|
#ifdef SUPPORT_GICC
|
|
*GIC_CPU_PriMask = SWAP32 (GIC_INT_ALL_ENABLED);
|
|
#else
|
|
#endif
|
|
/* split group priority and subpriority */
|
|
|
|
if (pVxbArmGicDrvCtrl != NULL)
|
|
{
|
|
if (pVxbArmGicDrvCtrl->intMode & INT_PREEMPT_MODEL)
|
|
{
|
|
#ifdef SUPPORT_GICC
|
|
*GIC_CPU_BinPoint = GIC_CPU_BINP_PREEMPT_VAL;
|
|
#else
|
|
sys_icc_bpr1_set(GIC_CPU_BINP_PREEMPT_VAL);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef SUPPORT_GICC
|
|
*GIC_CPU_BinPoint = SWAP32 (GIC_CPU_BINP_DEFAULT);
|
|
#else
|
|
sys_icc_bpr1_set(GIC_CPU_BINP_DEFAULT);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/* enable this processor's CPU interface */
|
|
#ifdef SUPPORT_GICC
|
|
*GIC_CPU_Control = SWAP32 (GIC_CONTROL_ENABLE);
|
|
#else
|
|
sys_icc_ctlr_set(GIC_CONTROL_ENABLE);
|
|
#endif
|
|
|
|
|
|
if (cpuNum == 0 && gicVersion < GIC_VERSION_GIC400)
|
|
{
|
|
|
|
/* enable distributor */
|
|
|
|
*GIC_Control = SWAP32(GIC_CONTROL_ENABLE);
|
|
}
|
|
#else /* _WRS_CONFIG_WRHV_GUEST */
|
|
|
|
/* RAB - for guest only enable distributor */
|
|
|
|
*GIC_Control = GIC_CONTROL_ENABLE;
|
|
|
|
#endif /* _WRS_CONFIG_WRHV_GUEST */
|
|
|
|
return OK;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* sysArmGicConnect - interrupt instance connect handler
|
|
*
|
|
* This function implements the connection of interrupt handler. It's used to
|
|
* support intConnect(...).
|
|
*
|
|
* NOTE:
|
|
*
|
|
* This routine is called somewhere by legacy driver.
|
|
*
|
|
* RETURNS: OK if operation succeed else ERROR
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS sysArmGicConnect
|
|
(
|
|
VOIDFUNCPTR * vector, /* interrupt vector to attach to */
|
|
VOIDFUNCPTR routine, /* routine to be called */
|
|
int parameter /* parameter to be passed to routine */
|
|
)
|
|
{
|
|
ARM_GIC_DRV_CTRL * pDrvCtrl = vxbGicId->pDrvCtrl;
|
|
|
|
if ((int)(vector) >= pDrvCtrl->gicLvlNum)
|
|
return(ERROR);
|
|
|
|
return(intCtlrISRAdd(&pDrvCtrl->isrHandle, (int)vector, routine,
|
|
(void *)parameter));
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbArmGicConnect - VxBus instance connect handler
|
|
*
|
|
* This function implements the VxBus InstConnect handler for an GIC instance.
|
|
*
|
|
* RETURNS: OK if operation succeed else ERROR
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS vxbArmGicConnect
|
|
(
|
|
VXB_DEVICE_ID pIntCtlr,
|
|
VXB_DEVICE_ID pDev,
|
|
int index,
|
|
void (*pIsr)(void * pArg),
|
|
void * pArg,
|
|
int * pInputPin
|
|
)
|
|
{
|
|
ARM_GIC_DRV_CTRL * pDrvCtrl = pIntCtlr->pDrvCtrl;
|
|
int inputPin;
|
|
|
|
/* get interrupt input pin */
|
|
|
|
inputPin = intCtlrPinFind (pDev, index, pIntCtlr, &pDrvCtrl->isrHandle);
|
|
|
|
if (inputPin == ERROR)
|
|
return (ERROR);
|
|
|
|
*pInputPin = inputPin;
|
|
|
|
/* assign the ISR and arg to the specified cpu input pin */
|
|
|
|
if (intCtlrISRAdd(&pDrvCtrl->isrHandle,
|
|
inputPin, pIsr, pArg) != OK)
|
|
return (ERROR);
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* sysArmGicDisconnect - disconnect a C routine from an interrupt
|
|
*
|
|
* This routine disconnects a specified C routine from a specified
|
|
* interrupt vector. It's used to support intDisconnect(...).
|
|
*
|
|
* This routine is called somewhere by legacy driver.
|
|
*
|
|
* RETURNS: OK, or ERROR if <vector> is out of range.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS sysArmGicDisconnect
|
|
(
|
|
VOIDFUNCPTR * vector, /* interrupt vector to detach from */
|
|
VOIDFUNCPTR routine, /* routine to be disconnected */
|
|
int parameter /* parameter to be matched */
|
|
)
|
|
{
|
|
ARM_GIC_DRV_CTRL * pDrvCtrl = vxbGicId->pDrvCtrl;
|
|
|
|
if ((int)(vector) >= pDrvCtrl->gicLvlNum)
|
|
return(ERROR);
|
|
|
|
return(intCtlrISRRemove(&pDrvCtrl->isrHandle, (int)vector, routine,
|
|
(void *)parameter));
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbArmGicDisconnect - disconnect device interrupt
|
|
*
|
|
* This routine disconnects the supplied routine and arg from the interrupt
|
|
* input found with intCtlrPinFind.
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
* RETURNS: OK if operation succeed else ERROR
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS vxbArmGicDisconnect
|
|
(
|
|
VXB_DEVICE_ID pIntCtlr,
|
|
VXB_DEVICE_ID pDev,
|
|
int index,
|
|
VOIDFUNCPTR pIsr,
|
|
void * pArg
|
|
)
|
|
{
|
|
ARM_GIC_DRV_CTRL * pDrvCtrl = pIntCtlr->pDrvCtrl;
|
|
int inputPin;
|
|
|
|
/* get interrupt input pin */
|
|
|
|
inputPin = intCtlrPinFind (pDev, index, pIntCtlr, &pDrvCtrl->isrHandle);
|
|
if (inputPin == ERROR)
|
|
return (ERROR);
|
|
|
|
/* remove the ISR and arg from the specified cpu input pin */
|
|
|
|
if (intCtlrISRRemove(&pDrvCtrl->isrHandle, inputPin, pIsr, pArg) != OK)
|
|
return (ERROR);
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* sysArmGicISREnable - enable interrupt handler
|
|
*
|
|
* This routine enables interrupt for the configured input pin
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
* RETURNS: OK if operation succeed else ERROR
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS sysArmGicISREnable
|
|
(
|
|
struct intCtlrHwConf * pEntries,
|
|
int inputPin
|
|
)
|
|
{
|
|
struct intCtlrISRChainEntry * pChain;
|
|
UINT32 flagValue;
|
|
VOIDFUNCPTR func;
|
|
|
|
/* make sure top-level enabled */
|
|
|
|
flagValue = intCtlrTableFlagsGet(pEntries, inputPin);
|
|
flagValue |= VXB_INTCTLR_FLG_ENABLE;
|
|
intCtlrTableFlagsSet(pEntries, inputPin, flagValue);
|
|
|
|
func = intCtlrTableIsrGet(pEntries, inputPin);
|
|
if ( func == intCtlrChainISR )
|
|
{
|
|
pChain = (struct intCtlrISRChainEntry *)
|
|
intCtlrTableArgGet(pEntries, inputPin);
|
|
while (pChain != NULL)
|
|
{
|
|
pChain->flags |= VXB_INTCTLR_FLG_ENABLE;
|
|
pChain = pChain->pNext;
|
|
}
|
|
}
|
|
|
|
return(OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* sysArmGicEnable - enable an interrupt handler from the vector table
|
|
*
|
|
* This routine enables interrupt handler from the vector table. It's used
|
|
* to support intEnable(...).
|
|
*
|
|
* This routine is called somewhere by legacy driver.
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
* RETURNS: OK if operation succeed else ERROR
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS sysArmGicEnable
|
|
(
|
|
int vector
|
|
)
|
|
{
|
|
ARM_GIC_DRV_CTRL *pDrvCtrl = vxbGicId->pDrvCtrl;
|
|
if ((int)(vector) >= pDrvCtrl->gicLvlNum)
|
|
return(ERROR);
|
|
|
|
if (sysArmGicISREnable(&(pDrvCtrl->isrHandle), vector) != OK)
|
|
return (ERROR);
|
|
|
|
vxbArmGicLvlEnable(pDrvCtrl->pInst, vector);
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbArmGicEnable - enable device interrupt
|
|
*
|
|
* This routine enables interrupt for the configured input pin
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
* RETURNS: OK if operation succeed else ERROR
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS vxbArmGicEnable
|
|
(
|
|
VXB_DEVICE_ID pIntCtlr,
|
|
VXB_DEVICE_ID pDev,
|
|
int index,
|
|
VOIDFUNCPTR pIsr,
|
|
void * pArg
|
|
)
|
|
{
|
|
ARM_GIC_DRV_CTRL * pDrvCtrl = pIntCtlr->pDrvCtrl;
|
|
int inputPin;
|
|
|
|
/* get interrupt input pin */
|
|
|
|
inputPin = intCtlrPinFind (pDev, index, pIntCtlr, &pDrvCtrl->isrHandle);
|
|
if (inputPin == ERROR)
|
|
return (ERROR);
|
|
|
|
/* enable ISR */
|
|
|
|
if (intCtlrISREnable(&pDrvCtrl->isrHandle, inputPin, pIsr, pArg) != OK)
|
|
return (ERROR);
|
|
|
|
vxbArmGicLvlEnable(pDrvCtrl->pInst, inputPin);
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* sysArmGicISRDisable - disable interrupt handler
|
|
*
|
|
* This routine disables interrupt for the configured input pin
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
* RETURNS: OK if operation succeed else ERROR
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS sysArmGicISRDisable
|
|
(
|
|
struct intCtlrHwConf * pEntries,
|
|
int inputPin
|
|
)
|
|
{
|
|
struct intCtlrISRChainEntry * pChain;
|
|
UINT32 flagValue;
|
|
VOIDFUNCPTR func;
|
|
|
|
/* make sure top-level disabled */
|
|
|
|
flagValue = intCtlrTableFlagsGet(pEntries, inputPin);
|
|
flagValue &= ~VXB_INTCTLR_FLG_ENABLE;
|
|
intCtlrTableFlagsSet(pEntries, inputPin, flagValue);
|
|
|
|
func = intCtlrTableIsrGet(pEntries, inputPin);
|
|
if ( func == intCtlrChainISR )
|
|
{
|
|
pChain = (struct intCtlrISRChainEntry *)
|
|
intCtlrTableArgGet(pEntries, inputPin);
|
|
while (pChain != NULL)
|
|
{
|
|
pChain->flags &= ~VXB_INTCTLR_FLG_ENABLE;
|
|
pChain = pChain->pNext;
|
|
}
|
|
}
|
|
|
|
return(OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* sysArmGicDisable - disable an interrupt handler from the vector table
|
|
*
|
|
* This routine disables interrupt handler from the vector table. It's used
|
|
* to support intDisable(...).
|
|
*
|
|
* This routine is called somewhere by legacy driver.
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
* RETURNS: OK if operation succeed else ERROR
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS sysArmGicDisable
|
|
(
|
|
int vector
|
|
)
|
|
{
|
|
ARM_GIC_DRV_CTRL *pDrvCtrl = vxbGicId->pDrvCtrl;
|
|
|
|
if ((int)(vector) >= pDrvCtrl->gicLvlNum)
|
|
return(ERROR);
|
|
|
|
if (sysArmGicISRDisable(&(pDrvCtrl->isrHandle), vector) != OK)
|
|
return (ERROR);
|
|
|
|
vxbArmGicLvlDisable(pDrvCtrl->pInst, vector);
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbArmGicDisable - disable device interrupt
|
|
*
|
|
* This routine disables interrupt for the configured input pin
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
* RETURNS: OK if operation succeed else ERROR
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS vxbArmGicDisable
|
|
(
|
|
VXB_DEVICE_ID pIntCtlr,
|
|
VXB_DEVICE_ID pDev,
|
|
int index,
|
|
VOIDFUNCPTR pIsr,
|
|
void * pArg
|
|
)
|
|
{
|
|
ARM_GIC_DRV_CTRL * pDrvCtrl = pIntCtlr->pDrvCtrl;
|
|
BOOL allDisabled;
|
|
int inputPin;
|
|
|
|
/* get interrupt input pin */
|
|
|
|
inputPin = intCtlrPinFind (pDev, index, pIntCtlr, &pDrvCtrl->isrHandle);
|
|
if (inputPin == ERROR)
|
|
return (ERROR);
|
|
|
|
/* disable ISR */
|
|
|
|
allDisabled = intCtlrISRDisable(&pDrvCtrl->isrHandle, inputPin, pIsr, pArg);
|
|
|
|
if (allDisabled)
|
|
vxbArmGicLvlDisable(pDrvCtrl->pInst, inputPin);
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbArmGicLvlVecChk - check for and return any pending interrupts
|
|
*
|
|
* This routine interrogates the hardware to determine the highest priority
|
|
* interrupt pending. It returns the vector associated with that interrupt,
|
|
* and also the level of that interrupt.
|
|
*
|
|
* This routine must be called with CPU interrupts disabled.
|
|
*
|
|
* The return value ERROR indicates that no pending interrupt was found and
|
|
* that the level and vector values were not returned.
|
|
*
|
|
* RETURNS: OK or ERROR if no interrupt is pending.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
#define ARM_GICV3_ICCIAR_INTID_MASK 0x3FF
|
|
#define ARM_GICV3_ICCIAR_INTID(val) \
|
|
((val) & ARM_GICV3_ICCIAR_INTID_MASK)
|
|
|
|
STATUS vxbArmGicLvlVecChk
|
|
(
|
|
VXB_DEVICE_ID pInst,
|
|
int * pLevel,
|
|
int * pVector
|
|
#ifdef _WRS_CONFIG_SMP
|
|
, int * pSrcCpuId
|
|
#endif
|
|
)
|
|
{
|
|
UINT32 currentLevel, levelBak;
|
|
|
|
/* read pending interrupt register and mask undefined bits */
|
|
#ifdef SUPPORT_GICC
|
|
levelBak = SWAP32(*GIC_CPU_IntAck);
|
|
#else
|
|
levelBak = sys_icc_iar1_get();
|
|
#endif
|
|
|
|
currentLevel = levelBak & GIC_INT_SPURIOUS;
|
|
|
|
/*
|
|
* If no interrupt is pending, register will have a value of 1023,
|
|
* return ERROR
|
|
*/
|
|
|
|
if (currentLevel == GIC_INT_SPURIOUS)
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
#ifdef _WRS_CONFIG_SMP
|
|
|
|
/* check if interrupt is IPI */
|
|
|
|
if(currentLevel < SGI_INT_MAX)
|
|
{
|
|
/*
|
|
* Level for IPI is defined and processed by software.
|
|
* Hardware always use 0 - SGI_INT_MAX as the IPI interrupt level.
|
|
* When we find that this is a SGI interrupt, we add armGicLinesNum to
|
|
* the current SGI level (0 - SGI_INT_MAX), in other words, the SGI
|
|
* level is redefined by software to declare that this is a specific
|
|
* interrupt, then we need save the source CPU ID to ack this interrupt.
|
|
*/
|
|
|
|
if (gicVersion >= GIC_VERSION_GIC400)
|
|
{
|
|
*pSrcCpuId = 0;
|
|
}
|
|
else
|
|
{
|
|
*pSrcCpuId = levelBak & GIC_SGI_SRC_CPU_ID_MASK;
|
|
}
|
|
*pLevel = (currentLevel + armGicLinesNum);
|
|
*pVector = IVEC_TO_INUM(currentLevel + armGicLinesNum);
|
|
|
|
}
|
|
else
|
|
#endif /* _WRS_CONFIG_SMP */
|
|
{
|
|
*pLevel = currentLevel;
|
|
|
|
/* fetch, or compute the interrupt vector number */
|
|
|
|
*pVector = IVEC_TO_INUM(currentLevel);
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbArmGicLvlVecAck - acknowledge the current interrupt
|
|
*
|
|
* This routine acknowledges the current interrupt cycle. The level and vector
|
|
* values are those generated during the vxbArmGicLvlVecChk() routine for this
|
|
* interrupt cycle.
|
|
*
|
|
* RETURNS: OK or ERROR if level is invalid.
|
|
*
|
|
* ERRNO
|
|
*/
|
|
STATUS vxbArmGicLvlVecAck
|
|
(
|
|
VXB_DEVICE_ID pInst,
|
|
int level, /* old interrupt level to be restored */
|
|
int vector /* current interrupt vector, if needed */
|
|
#ifdef _WRS_CONFIG_SMP
|
|
, int srcCpuId
|
|
#endif /* _WRS_CONFIG_SMP */
|
|
)
|
|
{
|
|
UINT32 maxIntLines;
|
|
|
|
#ifdef _WRS_CONFIG_SMP
|
|
maxIntLines = armGicLinesNum + ARM_GIC_IPI_COUNT;
|
|
#else
|
|
maxIntLines = armGicLinesNum;
|
|
#endif /* _WRS_CONFIG_SMP */
|
|
|
|
/* Validity check for level. */
|
|
|
|
if (level < 0 || level >= maxIntLines ||
|
|
(level >= SGI_INT_MAX && level < PPI_START_INT_NUM))
|
|
return ERROR;
|
|
|
|
/*
|
|
* Ack the interrupt. It's implemented on the CPU interface to the
|
|
* interrupt distributor.
|
|
*/
|
|
|
|
#ifdef _WRS_CONFIG_SMP
|
|
if (level >= armGicLinesNum)
|
|
{
|
|
/*
|
|
* SGI is used to implement the IPI. The source CPU ID must be carried
|
|
* to acknowledge the SGI interrupts.
|
|
*/
|
|
|
|
level -= armGicLinesNum;
|
|
if (gicVersion < GIC_VERSION_GIC400)
|
|
level |= srcCpuId;
|
|
}
|
|
#endif /* _WRS_CONFIG_SMP */
|
|
#ifdef SUPPORT_GICC
|
|
*GIC_CPU_EOInt = SWAP32( level );
|
|
#else
|
|
sys_icc_eoir1_set(level);
|
|
#endif
|
|
|
|
return OK;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbArmGicLvlChg - change the interrupt level value
|
|
*
|
|
* This routine sets the interrupt priority mask.
|
|
* All levels up to the specified level are disabled.
|
|
* All levels above the specified level will be enabled.
|
|
* This routine must be called with interrupts disabled.
|
|
*
|
|
* RETURNS: previous interrupt level or ERROR if level is invalid.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
int vxbArmGicLvlChg
|
|
(
|
|
VXB_DEVICE_ID pInst,
|
|
int level /* new interrupt level */
|
|
)
|
|
{
|
|
int oldLevel;
|
|
ARM_GIC_DRV_CTRL * pDrvCtrl;
|
|
|
|
/* if parameters are invalid, return ERROR */
|
|
|
|
if ((pInst == NULL) || (pInst->pDrvCtrl == NULL))
|
|
return (ERROR);
|
|
|
|
/* retrieve the data */
|
|
|
|
pDrvCtrl = (ARM_GIC_DRV_CTRL *)(pInst->pDrvCtrl);
|
|
|
|
oldLevel = pDrvCtrl->gicLvlCurrent;
|
|
|
|
if (level <= GIC_IPI_PRIORITY)
|
|
level = oldLevel;
|
|
if (level > armGicPriorityLvlMax)
|
|
level = armGicPriorityLvlMax;
|
|
|
|
/* change current interrupt level */
|
|
|
|
pDrvCtrl->gicLvlCurrent = level;
|
|
#ifdef SUPPORT_GICC
|
|
*GIC_CPU_PriMask = SWAP32 (level);
|
|
#else
|
|
#endif
|
|
VX_SYNC_BARRIER();
|
|
|
|
return oldLevel;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbArmGicLvlEnable - enable a single interrupt level
|
|
*
|
|
* This routine enables a specific interrupt level at the interrupt distributor.
|
|
* The enabled level will be allowed to generate an interrupt to the configured
|
|
* CPU(s). Without being enabled, the interrupt is blocked.
|
|
*
|
|
* RETURNS: OK or ERROR if level is invalid.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS vxbArmGicLvlEnable
|
|
(
|
|
VXB_DEVICE_ID pInst,
|
|
int level /* level to be enabled */
|
|
)
|
|
{
|
|
int key;
|
|
|
|
#ifdef _WRS_CONFIG_SMP
|
|
|
|
/*
|
|
* For SGI interrupt, we always return OK, since SGI interrupt can not be
|
|
* disabled.
|
|
*/
|
|
if ((level >= 0 && level < SGI_INT_MAX) ||
|
|
(level >= armGicLinesNum&& level < (armGicLinesNum + ARM_GIC_IPI_COUNT)))
|
|
{
|
|
if (gicVersion >= GIC_VERSION_GIC400)
|
|
{
|
|
|
|
if (level >= armGicLinesNum)
|
|
{
|
|
level -= armGicLinesNum;
|
|
}
|
|
|
|
key = intCpuLock (); /* LOCK INTERRUPTS */
|
|
|
|
*GICR_IntEnable = SWAP32 (BIT(level)); /* enable interrupt */
|
|
|
|
intCpuUnlock (key); /* UNLOCK INTERRUPTS */
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
/* validity check for interrupt number */
|
|
/* req: VX7-16254 */
|
|
if (level < 0 || level >= (armGicLinesNum + ARM_GIC_IPI_COUNT))
|
|
return ERROR;
|
|
#else
|
|
if ((level >= 0) && (level < SGI_INT_MAX))
|
|
return OK;
|
|
|
|
/* Validity check for level. */
|
|
|
|
if (level < PPI_START_INT_NUM || level >= armGicLinesNum )
|
|
return ERROR;
|
|
|
|
#endif
|
|
key = intCpuLock (); /* LOCK INTERRUPTS */
|
|
if ((gicVersion >= GIC_VERSION_GIC400) &&
|
|
(level < SPI_START_INT_NUM))
|
|
{
|
|
int cpuNum = vxCpuIndexGet();
|
|
*GICR_IntEnable_CPU(cpuNum) = SWAP32 (BIT(level)); /* enable interrupt */
|
|
}
|
|
else
|
|
{
|
|
*GIC_IntEnable (level) = SWAP32 (BIT(level)); /* enable interrupt */
|
|
}
|
|
|
|
intCpuUnlock (key); /* UNLOCK INTERRUPTS */
|
|
|
|
return OK;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbArmGicLvlDisable - disable a single interrupt level
|
|
*
|
|
* This routine disables a specific interrupt level at the interrupt distributor.
|
|
* The disabled level is prevented from generating an interrupts.
|
|
*
|
|
* RETURNS: OK or ERROR if level is invalid.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS vxbArmGicLvlDisable
|
|
(
|
|
VXB_DEVICE_ID pInst,
|
|
int level /* level to be disabled */
|
|
)
|
|
{
|
|
int key;
|
|
|
|
if ((level >= 0 && level < SGI_INT_MAX) ||
|
|
(level >= armGicLinesNum&& level < (armGicLinesNum + ARM_GIC_IPI_COUNT)))
|
|
{
|
|
if (gicVersion >= GIC_VERSION_GIC400)
|
|
{
|
|
|
|
if (level >= armGicLinesNum)
|
|
{
|
|
level -= armGicLinesNum;
|
|
}
|
|
|
|
key = intCpuLock (); /* LOCK INTERRUPTS */
|
|
|
|
*GICR_IntEnClr = SWAP32 (BIT(level)); /* enable interrupt */
|
|
|
|
intCpuUnlock (key); /* UNLOCK INTERRUPTS */
|
|
}
|
|
return OK;
|
|
}
|
|
/* Validity check for level. */
|
|
|
|
#ifdef _WRS_CONFIG_SMP
|
|
/* req: VX7-16258 */
|
|
if (level < PPI_START_INT_NUM|| level >= (armGicLinesNum + ARM_GIC_IPI_COUNT))
|
|
return ERROR;
|
|
#else
|
|
if (level < PPI_START_INT_NUM || level >= armGicLinesNum)
|
|
return ERROR;
|
|
#endif /* _WRS_CONFIG_SMP */
|
|
|
|
key = intCpuLock ();
|
|
if ((gicVersion >= GIC_VERSION_GIC400) &&
|
|
(level < SPI_START_INT_NUM))
|
|
{
|
|
int cpuNum = vxCpuIndexGet();
|
|
*GICR_IntEnClr_CPU(cpuNum) = SWAP32 (BIT(level)); /* disable interrupt */
|
|
}
|
|
else
|
|
{
|
|
*GIC_IntEnClr(level) = SWAP32( BIT(level));
|
|
}
|
|
|
|
intCpuUnlock (key);
|
|
|
|
return OK;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* vxbArmGicHwLvlChg - change the interrupt level value
|
|
*
|
|
* This routine sets the current interrupt level to the specified level.
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
* RETURNS: Previous interrupt level.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL int vxbArmGicHwLvlChg
|
|
(
|
|
int level
|
|
)
|
|
{
|
|
return vxbArmGicLvlChg(pVxbArmGicDrvCtrl->pInst,level);
|
|
}
|
|
|
|
#ifdef INCLUDE_SHOW_ROUTINES
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbArmGicDataShow - show data acquired by vxBus
|
|
*
|
|
* This routine shows data acquired by vxBus.
|
|
*
|
|
* RETURNS: N/A
|
|
*/
|
|
|
|
void vxbArmGicDataShow
|
|
(
|
|
VXB_DEVICE_ID pInst,
|
|
int *dummy
|
|
)
|
|
{
|
|
ARM_GIC_DRV_CTRL * pDrvCtrl;
|
|
|
|
/* check if parameters are invalid */
|
|
|
|
if ((pInst == NULL) || (pInst->pDrvCtrl == NULL))
|
|
return;
|
|
|
|
/* retrieve the data */
|
|
|
|
pDrvCtrl = (ARM_GIC_DRV_CTRL *)(pInst->pDrvCtrl);
|
|
|
|
printf ("\nGIC Configuration Data acquired by vxBus\n\n");
|
|
|
|
printf ("\n ARM GIC Info : \n");
|
|
|
|
printf (" pInst = 0x%08x\n", pInst);
|
|
|
|
printf (" GicBase = 0x%08x\n",
|
|
pDrvCtrl->gicBase);
|
|
printf (" GicLvlCurrent = 0x%08x\n",
|
|
pDrvCtrl->gicLvlCurrent);
|
|
printf (" gicDistOffset = 0x%08x\n",
|
|
pDrvCtrl->gicDistOffset);
|
|
printf (" gicCpuOffset = 0x%08x\n",
|
|
pDrvCtrl->gicCpuOffset);
|
|
}
|
|
|
|
#endif /* INCLUDE_SHOW_ROUTINES */
|
|
|
|
|
|
#ifdef _WRS_CONFIG_SMP
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbArmGicHwEnable - enable hardware interrupt
|
|
*
|
|
* This routine enables the interrupt for the configured input pin
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
* RETURNS: OK if operation succeed else ERROR
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS vxbArmGicHwEnable
|
|
(
|
|
int inputPin
|
|
)
|
|
{
|
|
return vxbArmGicLvlEnable(pVxbArmGicDrvCtrl->pInst, inputPin);
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* vxbArmGicHwDisable - disable device interrupt
|
|
*
|
|
* This routine disables the interrupt the configured input pin
|
|
*
|
|
* \NOMANUAL
|
|
*
|
|
* RETURNS: OK if operation succeed else ERROR
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS vxbArmGicHwDisable
|
|
(
|
|
int inputPin
|
|
)
|
|
{
|
|
return vxbArmGicLvlDisable(pVxbArmGicDrvCtrl->pInst, inputPin);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* sysArmGicDevInit - initialize interrupt controller.
|
|
*
|
|
* This routine initializes interrupt controller. It may be called by non-CPU0
|
|
* routines in BSP, or somewhere else.
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
void sysArmGicDevInit (void)
|
|
{
|
|
int cpuNum = vxCpuIndexGet();
|
|
|
|
(void)vxbArmGicIntDevInit(cpuNum);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbArmGicIntReroute - reroute interrupt to specified CPU
|
|
*
|
|
* This routine reroutes device interrupt to requested CPU. Note that the cpu is
|
|
* specified in a cpuset_t type, and this would allow for multiple cpus to be
|
|
* bundled with the interrupt. Multicore processor can ensure that only one CPU
|
|
* will be triggered if the interrupt occurs.
|
|
*
|
|
* RETURNS: OK if operation succeed else ERROR
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS vxbArmGicIntReroute
|
|
(
|
|
VXB_DEVICE_ID pDev,
|
|
int index,
|
|
cpuset_t destCpu
|
|
)
|
|
{
|
|
struct intCtlrHwConf * isrHandle;
|
|
BOOL flag;
|
|
int targCpu = 0;
|
|
int bitCnt = 0;
|
|
int i;
|
|
int inputPin;
|
|
int tmpData;
|
|
UINT32 oldIntCfg;
|
|
|
|
isrHandle = &(((ARM_GIC_DRV_CTRL *)(vxbGicId->pDrvCtrl))->isrHandle);
|
|
|
|
/* convert cpuset_t cpu number to numeric cpu number */
|
|
|
|
for (i = 0; i < ((ARM_GIC_DRV_CTRL *)(vxbGicId->pDrvCtrl))->gicCpuNum; i++)
|
|
{
|
|
if (destCpu & (1 << i))
|
|
{
|
|
bitCnt++;
|
|
targCpu = i;
|
|
}
|
|
}
|
|
|
|
/* make sure destCpu is a proper cpuset_t value */
|
|
|
|
if (bitCnt != 1)
|
|
return (ERROR);
|
|
|
|
/* find the device input pin number */
|
|
|
|
inputPin = intCtlrPinFind (pDev, index, vxbGicId, isrHandle);
|
|
if (inputPin == ERROR)
|
|
return (ERROR);
|
|
|
|
/* make sure pin is allocated */
|
|
|
|
VXB_INTCTLR_PINENTRY_ALLOCATED(isrHandle, inputPin, flag);
|
|
|
|
if (!flag)
|
|
return (ERROR);
|
|
|
|
oldIntCfg = SWAP32(*GIC_IntEnable(inputPin));
|
|
|
|
/* disable interrupt source */
|
|
|
|
vxbArmGicLvlDisable(pDev, inputPin);
|
|
|
|
if(gicVersion < GIC_VERSION_GIC400)
|
|
{
|
|
|
|
/* clear the current configuration */
|
|
|
|
tmpData = 0xff << ((inputPin % TARGETS_PER_WORD) * 8);
|
|
tmpData = SWAP32( *GIC_CPUTarg(inputPin) ) & ~tmpData;
|
|
|
|
/* set route bit */
|
|
|
|
tmpData |= ((UINT32) (0x1 << (UINT32)targCpu) << \
|
|
((inputPin % TARGETS_PER_WORD) * 8));
|
|
|
|
*GIC_CPUTarg(inputPin) = SWAP32( tmpData );
|
|
}
|
|
else
|
|
{
|
|
*GIC_IntRpute(i) = GIC_AFF_LOW32_MASK & vxCpuIdGetByIndex((UINT32)destCpu);
|
|
}
|
|
|
|
if ((oldIntCfg & SWAP32 (BIT (inputPin))) != 0)
|
|
{
|
|
/* enable interrupt source */
|
|
|
|
vxbArmGicLvlEnable(pDev, inputPin);
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbArmGicCpuReroute - reroute interrupts to specified CPU
|
|
*
|
|
* This routine reroutes interrupts that are configured in hwconf.c for a CPU
|
|
* other than the default CPU to that CPU.
|
|
*
|
|
* RETURNS: OK if operation succeed else ERROR
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS vxbArmGicCpuReroute
|
|
(
|
|
VXB_DEVICE_ID pDev,
|
|
void * destCpu
|
|
)
|
|
{
|
|
ARM_GIC_DRV_CTRL * pDrvCtrl = pDev->pDrvCtrl;
|
|
struct intCtlrHwConf *isrHandle = &(pDrvCtrl->isrHandle);
|
|
int i;
|
|
int configCpu, tmpData;
|
|
BOOL flag;
|
|
void (*func)();
|
|
|
|
if ((int)destCpu >= pDrvCtrl->gicCpuNum)
|
|
return (ERROR);
|
|
|
|
/* move interrupts to requested cpu */
|
|
|
|
for (i = 0; i < armGicLinesNum; i++)
|
|
{
|
|
/* verify this is an allocated pin so NULL references are avoided */
|
|
|
|
VXB_INTCTLR_PINENTRY_ALLOCATED(isrHandle, i, flag);
|
|
|
|
if (flag)
|
|
{
|
|
/* only move interrupts that are configured with an ISR */
|
|
|
|
GIC_ISR(isrHandle, i, func);
|
|
|
|
if (func == NULL || func == intCtlrStrayISR)
|
|
continue;
|
|
|
|
/* move interrupts that are configured for the requested CPU */
|
|
|
|
GIC_DESTCPU(isrHandle, i, configCpu);
|
|
|
|
if (configCpu == (int)destCpu)
|
|
{
|
|
/* disable interrupt source */
|
|
|
|
vxbArmGicLvlDisable(pDev, i);
|
|
|
|
if(gicVersion < GIC_VERSION_GIC400)
|
|
{
|
|
|
|
/* clear the current configuration */
|
|
|
|
tmpData = 0xff << ((i % TARGETS_PER_WORD) * 8);
|
|
tmpData = SWAP32( *GIC_CPUTarg(i) ) & ~tmpData;
|
|
|
|
/* set route bit */
|
|
|
|
tmpData |= ((UINT32) (0x1 << (UINT32)destCpu) << \
|
|
((i % TARGETS_PER_WORD) * 8));
|
|
|
|
*GIC_CPUTarg(i) = SWAP32( tmpData );
|
|
}
|
|
else
|
|
{
|
|
*GIC_IntRpute(i) = GIC_AFF_LOW32_MASK & vxCpuIdGetByIndex((UINT32)destCpu);
|
|
}
|
|
|
|
|
|
/* enable interrupt source */
|
|
|
|
vxbArmGicLvlEnable(pDev, i);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
return (OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbArmGicIpiCtlGet - retrieve IPI control structure
|
|
*
|
|
* This routine retrieves IPI control structure.
|
|
*
|
|
* RETURNS: pointer of IPI control structure
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL VXIPI_CTRL_INIT * vxbArmGicIpiCtlGet
|
|
(
|
|
VXB_DEVICE_ID pInst,
|
|
void * pArg
|
|
)
|
|
{
|
|
vxArmGicIpiCtrlInit.pCpus = sysCpuAvailableGet();
|
|
vxArmGicIpiCtrlInit.pCtlr = pInst;
|
|
|
|
return(&vxArmGicIpiCtrlInit);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* The inline assembly to access generic system register on c12 follows diab's inline
|
|
* assembly syntax, so diab compiler must be used.
|
|
*/
|
|
|
|
#ifdef __DCC__
|
|
|
|
_WRS_INLINE void armGicIpiGen
|
|
(
|
|
UINT32 valLow, UINT32 valHigh
|
|
)
|
|
{
|
|
__inline__ArmGicIpiGen (valLow, valHigh);
|
|
}
|
|
#else
|
|
#ifndef _WRS_CONFIG_LP64
|
|
void __inline__ArmGicIpiGen (UINT32 valLow, UINT32 valHigh)
|
|
{
|
|
__asm__ __volatile__ ("MCRR p15,0,%0,%1,c12"
|
|
:
|
|
: "r" (valLow), "r" (valHigh));
|
|
}
|
|
|
|
_WRS_INLINE void armGicIpiGen
|
|
(
|
|
UINT32 valLow, UINT32 valHigh
|
|
)
|
|
{
|
|
__inline__ArmGicIpiGen (valLow, valHigh);
|
|
}
|
|
#else
|
|
_WRS_INLINE void armGicIpiGen (UINT32 valLow, UINT32 valHigh)
|
|
{
|
|
UINT64 tempVal= valLow | ((UINT64)valHigh << 32);
|
|
__asm__ __volatile__ ("MSR ICC_SGI0R_EL1, %0"
|
|
:
|
|
: "r" (tempVal));
|
|
}
|
|
#endif /* _WRS_CONFIG_LP64 */
|
|
#endif /* !__DCC__ */
|
|
/*******************************************************************************
|
|
*
|
|
* vxbArmGicIpiGen - generate Inter Processor Interrupt
|
|
*
|
|
* This routine generates Inter Processor Interrupt(IPI) through
|
|
* Software Generated Interrupt(SGI)
|
|
*
|
|
* RETURNS: OK or ERROR if parameter is invalid.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS vxbArmGicIpiGen
|
|
(
|
|
VXB_DEVICE_ID pCtlr,
|
|
INT32 ipiId,
|
|
cpuset_t cpus
|
|
)
|
|
{
|
|
|
|
int index;
|
|
UINT8 aff1;
|
|
UINT8 aff2;
|
|
UINT8 cpuList;
|
|
UINT32 cpuId;
|
|
volatile UINT32 lowWord = 0;
|
|
volatile UINT32 highWord = 0;
|
|
if (ipiId < 0 || ipiId >= ARM_GIC_IPI_COUNT || cpus == 0)
|
|
return (ERROR);
|
|
if (gicVersion >= GIC_VERSION_GIC400)
|
|
{
|
|
|
|
for(index = 0; index < 32; index ++)
|
|
{
|
|
if ((cpus >> index) & 0x1)
|
|
{
|
|
lowWord = 0;
|
|
highWord = 0 ;
|
|
cpuId = vxCpuIdGetByIndex(index);
|
|
cpuList = (UINT8)(cpuId & 0xff);
|
|
aff1 = (UINT8)((cpuId >> 8) & 0xff);
|
|
aff2 = (UINT8)((cpuId >> 16) & 0xff);
|
|
cpuList = 1 <<cpuList;
|
|
lowWord |= cpuList;
|
|
lowWord |= (ipiId & ipiId_MASK) << 24 ;
|
|
lowWord |= aff1 << 16;
|
|
highWord|= aff2 ;
|
|
armGicIpiGen (lowWord, highWord);
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
*GIC_SWInterrupt = SWAP32(cpus << 16 | ipiId);
|
|
}
|
|
|
|
return(OK);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbArmGicIpiConnect - connect ISR to IPI
|
|
*
|
|
* This routine connects ISR to Inter Processor Interrupt(IPI)
|
|
*
|
|
* RETURNS: return value of intConnect()
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS vxbArmGicIpiConnect
|
|
(
|
|
VXB_DEVICE_ID pCtlr,
|
|
INT32 ipiId,
|
|
IPI_HANDLER_FUNC ipiHandler,
|
|
void * ipiArg
|
|
)
|
|
{
|
|
INT32 level;
|
|
|
|
level = ipiId + armGicLinesNum;
|
|
|
|
return (intCtlrISRAdd(&pVxbArmGicDrvCtrl->isrHandle,
|
|
level, ipiHandler, ipiArg));
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbArmGicIpiDisconnect - disconnect ISR from IPI
|
|
*
|
|
* This routine disconnects ISR from Inter Processor Interrupt(IPI)
|
|
*
|
|
* RETURNS: OK if operation succeed else ERROR
|
|
*
|
|
* ERRNO:
|
|
*/
|
|
|
|
LOCAL STATUS vxbArmGicIpiDisconnect
|
|
(
|
|
VXB_DEVICE_ID pCtlr,
|
|
INT32 ipiId,
|
|
IPI_HANDLER_FUNC ipiHandler,
|
|
void * ipiArg
|
|
)
|
|
{
|
|
INT32 level;
|
|
|
|
level = ipiId + armGicLinesNum;
|
|
|
|
return (intCtlrISRRemove(&pVxbArmGicDrvCtrl->isrHandle,
|
|
level, ipiHandler, ipiArg));
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbArmGicIpiEnable - enable specified IPI
|
|
*
|
|
* This routine enables specified IPI
|
|
*
|
|
* RETURNS: return value of intEnable()
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS vxbArmGicIpiEnable
|
|
(
|
|
VXB_DEVICE_ID pCtlr,
|
|
INT32 ipiId
|
|
)
|
|
{
|
|
return (vxbArmGicHwEnable(ipiId));
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbArmGicIpiDisable - disable specified IPI
|
|
*
|
|
* This routine disables specified IPI
|
|
*
|
|
* RETURNS: return value of intDisable()
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS vxbArmGicIpiDisable
|
|
(
|
|
VXB_DEVICE_ID pCtlr,
|
|
INT32 ipiId
|
|
)
|
|
{
|
|
return (vxbArmGicHwDisable(ipiId));
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbArmGicIpiPrioGet - retrieve IPI priority
|
|
*
|
|
* This routine gets the current priority of specified IPI.
|
|
*
|
|
* NOTE
|
|
* priority configuration is currently unsupported, and we always use 0 as the
|
|
* priority of all IPIs.
|
|
*
|
|
* RETURNS: always 0
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL INT32 vxbArmGicIpiPrioGet
|
|
(
|
|
VXB_DEVICE_ID pCtlr,
|
|
INT32 ipiId
|
|
)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* vxbArmGicIpiPrioSet - set IPI priority
|
|
*
|
|
* This routine sets the priority of specified IPI.
|
|
*
|
|
* NOTE
|
|
* priority configuration is currently unsupported, and we always use 0 as the
|
|
* priority of all IPIs.
|
|
*
|
|
* RETURNS: always OK
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
LOCAL STATUS vxbArmGicIpiPrioSet
|
|
(
|
|
VXB_DEVICE_ID pCtlr,
|
|
INT32 ipiId,
|
|
INT32 prio
|
|
)
|
|
{
|
|
return (OK);
|
|
}
|
|
#endif /* _WRS_CONFIG_SMP */
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* sysMaxIntLvl - Get maximum Interrupt Level
|
|
*
|
|
* This routine retrieves maximum Interrupt Level. It is a debug function. Do not
|
|
* use "maxIntLvl" in hwconf.c with immediate value. Read it from GIC register.
|
|
*
|
|
* RETURNS: maximum Interrupt Level
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
UINT32 sysMaxIntLvl(void)
|
|
{
|
|
return armGicLinesNum;
|
|
}
|
|
|