?? sysepic.c
/* sysEpic.c - Driver for Embedded Programmable Interrupt Controller */
/* Copyright 1984-1999 Wind River Systems, Inc. */
#include "copyright_wrs.h"
/*
modification history
--------------------
01b,01apr02,jnz added support for 8245/8241 on chip duarts.
01a,10oct99,mtl written from SPS/Motorola by teamF1
*/
/*
DESCRIPTION
This module implements the Embedded Programmable Interrupt Controller (EPIC)
driver for the PPMC 8240 on the Sandpoint board.
The EPIC is an integrated interrupt controller in the 8240 which
provides following major capabilities:
Support for five external interrupt sources or one serial-style
interrupt (16 interrupt sources)
Support for connection of external interrupt controller device e.g. 8259
which is implemented as a part of a via chip.
16 programmable interrupt priority levels
Fully-nested interrupt delivery
Spurious vector generation
EPIC features are customized by writing into general control registers
or into interrupt level specific registers (IVPRs).
This driver allows a basic interface to the EPIC such as intializing it,
setting interrupt vectors, priorities, level/edge sense and interrupt
polarities, as well as enabling and disabling specific interrupts.
This driver implements a complete interrupt architecture system, complete
with vector table.
This driver provides the vector table for the system. It can support
a total of 256 vectors. In this driver the EPIC controller device can only
generate 5 different vectors, one for each external interrupt.
Other interrupt controllers such as the via on the Sandpoint 8240
can be connected to one of the above external interrupts.
The actual vector number corresponding to IRQ0
is determined by the value in sysVectorIRQ0 at initialization time. The
other vector numbers are generated by adding the IRQ number to this vector
number. For the Sandpoint PMMC8240, the value of sysVectorIRQ0 is
initialized from a constant INT_NUM_IRQ0, which is = 0x10 (16). So
all IRQs above 16 are assumed to be controlled by an external
interrupt controller such as a the Via vt82c686.
Lower IRQ's are controlled by the 8240's embedded programmable interrupt
controller or EPIC.
Although the EPIC has 5 external interrupts sources, only 4 are available
from the PPMC unit.
Since interrupt vectors can be shared, this driver does provide for
overloading of interrupt routines (i.e. there is
a list of interrupt routines for each interrupt vector (level)). To service
a vector requires that all connected interrupt routines be called in order
of their connection.
The following diagram shows an example of how interrupts can
be configured in this system.
EPIC Vector table
0 |-------|
|-------|
|-------|
|-------|---------------------
|-------| |
5 |-------| |
|-------| | IRQ 2 handler
|
.... -----------------------------------
| |
sysVectorIRQ0=16 | |
16 |-------| | |
|-------|<--------via Interrupt handler PCI slot 3 interrupt handler
|-------| Cascaded 8259s
|-------|
|-------|
|-------|
32 |-------|
....
|-------|
|-------|
|-------|
|-------|
|-------|
|-------|
256|-------|
If there are other devices in the system capable of generating their own
vectors then we presume that an appropriate interrupt handler is created
and attached to the vector associated with the correct IRQ number. That
interrupt handler would get a new vector directly from the device and then
call all of the handlers attached to that new vector. Vector information is
stored in a linked list of INT_HANDLER_DESC structures. The sysIntTbl array
contains a pointer to the first entry for each vector.
An example would be a VME interface chip.
If the VME chip interrupts the CPU on IRQ8, then the BSP should create
a special VME interrupt handler and attach it to vector # (sysVectorIRQ0 + 8).
When the handler is called, it should get the new vector from the VME
device. It will then use that new vector # to locate the specific VME
device handler routine from sysIntTbl. The VME interrupt handler will
call each handler connected to the devices vector. Note that the user
must insure that no VME device uses a vector that matches the vector used
by the VME interface chip itself. This could cause an infinite loop to
be generated.
.CS
/@ This is the sample VME interrupt handler (IRQ8) @/
VOID sysVmeHandler (void)
{
INT_HANDLER_DEC * pVector;
int newVec;
newVec = ????; /@ get real vector from device @/
/@ if no VME interrupt is present, exit immediately @/
if (newVec < 0 || newVec > 255)
return;
/@ process all connected routines @/
pVector = sysIntTbl[newVec];
while (pVector != NULL)
{
(*pVector->vec) (pVector->arg);
pVector = pVector->next;
}
}
/@ The BSP would connect the VME handler to the vector for IRQ 8 @/
#define SYS_VME_VEC (sysVectorIRQ0 + 8) /@ IRQ8 @/
...
intConnect (INUM_TO_IVEC(SYS_VME_VEC), sysVmeHandler, 0);
...
.CE
.SH INITIALIZATION
This driver is initialized from the BSP, usually as part of sysHwInit().
The first routine to be called is sysEpicInit(). The routine resets the
global configuration register and resets the epic registers to default
values.
The second routine to be called is sysEpicIntrInit(). This routine takes no
arguments. This routine allocates the vector table and initializes the
chips to a default state. All individual interrupt sources are disabled.
Each has to be individually enabled by intEnable() before it will be
unmasked and allowed to generate an interrupt.
.SH CUSTOMIZING THIS DRIVER
The macros CPU_INT_LOCK() and CPU_INT_UNLOCK provide the access
to the CPU level interrupt lock/unlock routines. We presume that there
is a single interrupt line to the CPU. By default these macros call
intLock() and intUnlock() respectively.
*/
/* includes */
#include "vxWorks.h"
#include "sysEpic.h"
#include "mpc107.h"
#include "sysLib.h"
#include "stdio.h"
#include "string.h"
#ifdef INCLUDE_WINDVIEW
#include "private/eventP.h"
#endif
/* defines */
#ifndef CPU_INT_LOCK
# define CPU_INT_LOCK(pData) \
(*pData = intLock ())
#endif
#ifndef CPU_INT_UNLOCK
# define CPU_INT_UNLOCK(data) \
(intUnlock (data))
#endif
/* externs */
IMPORT STATUS excIntConnect (VOIDFUNCPTR *, VOIDFUNCPTR);
#if FALSE /* defined(INCLUDE_WINDVIEW) || defined(INCLUDE_INSTRUMENTATION) */
IMPORT int evtTimeStamp; /* Windview 1.0 only */
#endif
/* get the interrupt hook routines prototypes*/
IMPORT STATUS (*_func_intConnectRtn) (VOIDFUNCPTR *, VOIDFUNCPTR, int);
IMPORT int (*_func_intEnableRtn) (int);
IMPORT int (*_func_intdisableRtn) (int);
/* globals */
INT_HANDLER_DESC * sysIntTbl [INTERRUPT_TABLESIZE]; /* system interrupt tbl */
int epicIntTrace = 0; /* epic internal interrupts trace */
/* locals */
/* forward declarations */
LOCAL STATUS sysEpicIntConnect (VOIDFUNCPTR * vector, VOIDFUNCPTR routine,
int parameter);
LOCAL STATUS sysEpicIntEnable (int intNum);
LOCAL STATUS sysEpicIntDisable (int intNum);
LOCAL void sysEpicIntHandler (void);
/*******************************************************************************
*
* sysEpicInit - initialize the epic controller
*
* This routine resets the global Configuration Register, thus it:
* - disables all interrupts
* - sets epic registers to reset values
*
* It then sets the EPIC operation mode to Mixed Mode (vs. Pass Through
* mode). At this point only mixed mode is supported which means the EPIC
* is not configured for the pass through mode.
*
* Input:
* - <irqType> is either Direct IRQs (0) or Serial Interrupt IRQs (1).
* - <clkRatio> is clock frequency driving the serial interrupt
* interface.
*
* If irqType is Direct IRQs:
* - irqType is written to the SIE bit of the EPIC Interrupt
* Configuration register.
* - clkRatio is ignored.
*
* If irqType is Serial IRQs:
* - both irqType and clkRatio will be written to the EPIC
* Interrupt Configuration register.
*
* NOMANUAL
*
* RETURNS: N/A
*/
void sysEpicInit
(
ULONG irqType, /* irq type to initialize with */
ULONG clkRatio /* clock ratio */
)
{
ULONG gcrVal;
ULONG icrVal;
int irq;
int i = 0;
gcrVal = sysEUMBBARRead (EPIC_GLOBAL_REG);
gcrVal |= (EPIC_GCR_RESET);
sysEUMBBARWrite (EPIC_GLOBAL_REG, gcrVal);
/* wait for the reset sequence to be completed */
while (sysEUMBBARRead (EPIC_GLOBAL_REG) & EPIC_GCR_RESET)
{
i++;
if(i>0x100000)
{
logMsg("EPIC Reset error!\n",0,0,0,0,0,0);
break;
}
/* do nothing */
}
gcrVal = sysEUMBBARRead (EPIC_GLOBAL_REG);
gcrVal |= (EPIC_GCR_MODE_MIXED); /* configure for mixed mode */
sysEUMBBARWrite (EPIC_GLOBAL_REG, gcrVal);
icrVal = sysEUMBBARRead (EPIC_INT_CONF_REG); /* read EICR */
if (irqType == EPIC_DIRECT_IRQ)
{
icrVal &= ~(EPIC_ICR_SEI); /* disable serial mode interrupts */
}
else /* serial mode is configured */
{
if (clkRatio != 0)
{
icrVal |= EPIC_ICR_CLK_RATIO (clkRatio);
}
}
sysEUMBBARWrite (EPIC_INT_CONF_REG, icrVal);
i = 0;
while (epicIntAck() != 0xff) /* Clear all pending interrupt */
{
i++;
if(i>0x100000)
{
logMsg("EPIC Clear all pending interrupt error!\n",0,0,0,0,0,0);
break;
}
/* do nothing */
}
/* init all IVPRs to sense = 1, polarity = defined, vec = 0, prio = 0 */
for (irq = 0; irq < EPIC_MAX_EXT_IRQS; irq++)
{
epicIntDisable (EPIC_VEC_REG(irq));
epicIntSourceSet (EPIC_VEC_REG(irq), EPIC_INT_POLARITY,
EPIC_SENSE_LVL, 0x0, 0x0);
}
#ifdef INCLUDE_DUART
/* init duart interrupts */
epicIntDisable (EPIC_DUART1_INT_VEC_REG);
epicIntSourceSet (EPIC_DUART1_INT_VEC_REG, EPIC_INT_POLARITY, \
EPIC_SENSE_LVL, 0x0, EPIC_DUART1_INT_VECT);
epicIntDisable (EPIC_DUART2_INT_VEC_REG);
epicIntSourceSet (EPIC_DUART2_INT_VEC_REG, EPIC_INT_POLARITY, \
EPIC_SENSE_LVL, 0x0, EPIC_DUART2_INT_VECT);
#endif /* INCLUDE_DUART */
epicCurTaskPrioSet (EPIC_PRIORITY_MAX); /* set it to highest priority */
}
/*******************************************************************************
*
* sysEpicIntrInit - initialize the interrupt table
*
* This function initializes the interrupt mechanism of the board.
*
* RETURNS: OK, always.
*/
STATUS sysEpicIntrInit (void)
{
int vector;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -