⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mpc107epic.c

📁 LoPEC Early Access VxWorks BSP
💻 C
字号:
/* mpc107Epic.c - EPIC Interrupt Controller driver *//* Copyright 1984-2000 Wind River Systems, Inc. *//* Copyright 1996,1997,1998,1999,2000 Motorola, Inc., All Rights Reserved */#include "copyright_wrs.h"/*modification history--------------------01c,30nov00,djs  changes made during board bringup01b,14nov00,djs  add IBC support01a,02nov00,djs  created from 01e,15jun00,dmw mv2100/kahluaEpic.c*//*DESCRIPTIONThis module implements the EPIC interrupt controller functionality.*//* includes */#include "mpc107.h"#include "mpc107Epic.h"/* defines *//* globals */IMPORT STATUS	      (*_func_intConnectRtn) (VOIDFUNCPTR *, VOIDFUNCPTR, int);IMPORT int	      (*_func_intEnableRtn) (int);IMPORT int	      (*_func_intDisableRtn) (int);IMPORT UINT32 		sysPciInLong (UINT32);IMPORT void   		sysPciOutLong (UINT32, UINT32);IMPORT STATUS		excIntConnect (VOIDFUNCPTR *, VOIDFUNCPTR);IMPORT UINT		sysGetMpuSpd(void);void			sysEpicIntHandler (void);/* system interrupt table */#define SYSTEM_INTERRUPT_TABLE_SIZE     256INT_HANDLER_DESC * sysIntTbl [SYSTEM_INTERRUPT_TABLE_SIZE];#ifdef INCLUDE_INSTRUMENTATION    IMPORT	int             evtTimeStamp;#endif /* INCLUDE_INSTRUMENTATION *//* forward declarations */LOCAL int       getEpicVecAddr (int);LOCAL STATUS	sysEpicIntConnect (VOIDFUNCPTR * vector, VOIDFUNCPTR routine,                                   int parameter);LOCAL int	sysEpicIntEnable (int);LOCAL int	sysEpicIntDisable (int);#ifndef CPU_INT_LOCK#   define CPU_INT_LOCK(x) \	(*x = intLock ())#endif /* CPU_INT_LOCK */#ifndef CPU_INT_UNLOCK#   define CPU_INT_UNLOCK(data) \	(intUnlock (data))#endif /* CPU_INT_UNLOCK */#include "sysIbc.c"/******************************************************************************** sysEpicInit - initialize the EPIC** This function initializes the Embedded Programmable Interrupt Controller * (EPIC) contained in the MPC107 chip.** It first initializes the system vector table, connects the EPIC interrupt* handler to the PPC external interrupt and attaches the local EPIC routines* for interrupt connecting, enabling and disabling to the corresponding system* routine pointers.** It then initializes the EPIC registers, clears any pending EPIC interrupts,* and enables interrupt handling by the EPIC.** RETURNS: OK always*/STATUS sysEpicInit (void)    {    int			i;    UINT32 temp = 0;    UINT32 nirq;    /* Initialize the interrupt table */    for (i = 0; i < SYSTEM_INTERRUPT_TABLE_SIZE; i++)        sysIntTbl[i] = NULL;     /* connect the interrupt demultiplexer to the PowerPC external interrupt */    excIntConnect ((VOIDFUNCPTR *) _EXC_OFF_INTR, sysEpicIntHandler);    /* attach the BSP specific routines to the operating system.  */    _func_intConnectRtn = sysEpicIntConnect;    _func_intEnableRtn = sysEpicIntEnable;    _func_intDisableRtn = sysEpicIntDisable;    /* Reset the EPIC */    sysPciOutLong((UINT32)EPIC_GLOBAL_CONFIG_REG, EPIC_GC_RESET);    /* Put the EPIC in mixed mode */    sysPciOutLong((UINT32)EPIC_GLOBAL_CONFIG_REG, EPIC_GC_MIXED);    /* Initialize the global timer frequency to the MPU speed. */    sysPciOutLong((UINT32)EPIC_TIMER_FREQ_REG, sysGetMpuSpd());    /* Initialze the 4 global timer interrupt sources */    sysPciOutLong((UINT32)EPIC_TIMER0_VEC_PRI_REG, INIT_TMR_SRC0);    sysPciOutLong((UINT32)EPIC_TIMER1_VEC_PRI_REG, INIT_TMR_SRC1);    sysPciOutLong((UINT32)EPIC_TIMER2_VEC_PRI_REG, INIT_TMR_SRC2);    sysPciOutLong((UINT32)EPIC_TIMER3_VEC_PRI_REG, INIT_TMR_SRC3);    /* Initialize the 16 serial interrupt sources */    sysPciOutLong((UINT32)EPIC_SER_SRC0_VEC_PRI_REG, INIT_SER_SRC0);    sysPciOutLong((UINT32)EPIC_SER_SRC1_VEC_PRI_REG, INIT_SER_SRC1);    sysPciOutLong((UINT32)EPIC_SER_SRC2_VEC_PRI_REG, INIT_SER_SRC2);    sysPciOutLong((UINT32)EPIC_SER_SRC3_VEC_PRI_REG, INIT_SER_SRC3);    sysPciOutLong((UINT32)EPIC_SER_SRC4_VEC_PRI_REG, INIT_SER_SRC4);    sysPciOutLong((UINT32)EPIC_SER_SRC5_VEC_PRI_REG, INIT_SER_SRC5);    sysPciOutLong((UINT32)EPIC_SER_SRC6_VEC_PRI_REG, INIT_SER_SRC6);    sysPciOutLong((UINT32)EPIC_SER_SRC7_VEC_PRI_REG, INIT_SER_SRC7);    sysPciOutLong((UINT32)EPIC_SER_SRC8_VEC_PRI_REG, INIT_SER_SRC8);    sysPciOutLong((UINT32)EPIC_SER_SRC9_VEC_PRI_REG, INIT_SER_SRC9);    sysPciOutLong((UINT32)EPIC_SER_SRC10_VEC_PRI_REG, INIT_SER_SRC10);    sysPciOutLong((UINT32)EPIC_SER_SRC11_VEC_PRI_REG, INIT_SER_SRC11);    sysPciOutLong((UINT32)EPIC_SER_SRC12_VEC_PRI_REG, INIT_SER_SRC12);    sysPciOutLong((UINT32)EPIC_SER_SRC13_VEC_PRI_REG, INIT_SER_SRC13);    sysPciOutLong((UINT32)EPIC_SER_SRC14_VEC_PRI_REG, INIT_SER_SRC14);    sysPciOutLong((UINT32)EPIC_SER_SRC15_VEC_PRI_REG, INIT_SER_SRC15);    /* Initialize the 2 DMA interrupt sources */    sysPciOutLong((UINT32)EPIC_DMA_CHAN0_INTR_VEC_SRC, INIT_DMA_SRC0);    sysPciOutLong((UINT32)EPIC_DMA_CHAN1_INTR_VEC_SRC, INIT_DMA_SRC1);    /* Initialize the I2C unit interrupt source */    sysPciOutLong((UINT32)EPIC_I2C_INTR_VEC_SRC, INIT_I2C_SRC);    /* Initialize the message unit interrupt source. */    sysPciOutLong((UINT32)EPIC_MSG_UNIT_INTR_VEC_SRC, INIT_MSGUNIT_SRC);    /* Set to serial-interrupt mode (16 sources) and clock ratio to 4. */    sysPciOutLong((UINT32)EPIC_INTR_CONFIG_REG, 				(EPIC_IC_R_VALUE << EPIC_IC_R_SHFT) |                                EPIC_IC_SIE);    /* Find out the maximum number of interrupt sources supported */    nirq = (((sysPciInLong((UINT32)EPIC_FEATURE_REG)) & 0x00ff0000) >> 16 );    /* Clear all interrupts pending and in-service registers */    for (i = 0; i < nirq; i++)	{        temp = sysPciInLong((UINT32)EPIC_IACK_REG);        sysPciOutLong((UINT32)EPIC_EOI_REG, 0);	}    /* Enable interrupts for this processor (1 and above). */    sysPciOutLong((UINT32)EPIC_CUR_TASK_PRI_REG, EPIC_TASK_PRI_1);    return(OK);    }/******************************************************************************** sysEpicIntConnect - connect an interrupt handler to the system vector table** This function connects an interrupt handler to the system vector table.** RETURNS: OK/ERROR.*/LOCAL STATUS sysEpicIntConnect    (    VOIDFUNCPTR *      vector,         /* interrupt vector to attach */    VOIDFUNCPTR        routine,        /* routine to be called */    int                parameter       /* parameter to be passed to routine */    )    {    INT_HANDLER_DESC * newHandler;    INT_HANDLER_DESC * currHandler;    LOCAL_INT_DATA     connect;    static BOOL        firstTime = TRUE;    /* validate the vector */    if (((int)vector < 0) || ((int)vector > (SYSTEM_INTERRUPT_TABLE_SIZE - 1)))        return (ERROR);    if (firstTime)        {         /* connect the PIB to MPIC, before any other connections */         firstTime = FALSE;        sysIbcMpicConnect (); /* calls this rtn, recursively */        }     /* create a new interrupt handler */    if ((newHandler = (INT_HANDLER_DESC *)calloc (1, sizeof (INT_HANDLER_DESC)))	 == NULL)        return (ERROR);     /* initialize the new handler */    newHandler->vec  = routine;    newHandler->arg  = parameter;    newHandler->next = NULL;    /* install the handler in the system interrupt table */    if (sysIntTbl[(int)vector] == NULL)        {        sysIntTbl[(int)vector] = newHandler; /* single int. handler case */        }    else        {        currHandler = sysIntTbl[(int)vector]; /* multiple int. handler case */        while (currHandler->next != NULL)            {            currHandler = currHandler->next;            }        currHandler->next = newHandler;        }    /*      * if the connect is for an EPIC interrupt,      * then store the vector into the appropriate EPIC vector register     */    connect.regAddr = getEpicVecAddr((int)vector);    if (connect.regAddr > 0)        {        /* read the vector register */        connect.regVal = sysPciInLong((UINT32)(connect.regAddr));        /* store the interrupt vector number */        connect.regVal |= (int)vector;        /* write the contents of the vector register back */        sysPciOutLong((UINT32)(connect.regAddr), connect.regVal);        }    return (OK);    }/******************************************************************************** sysEpicIntEnable - enable an Epic interrupt level** This routine enables a specified Epic interrupt level.** RETURNS: OK or ERROR if interrupt level not supported*/LOCAL int sysEpicIntEnable    (    int intLevel        /* interrupt level to enable */    )    {    LOCAL_INT_DATA	enable;    /* Validate vector.  */    /*     * if the int. level is not for ISA or MPIC, then it is not supported.     * If not supported, just return.     */    if ((intLevel < EPIC_INTERRUPT_BASE) || 		(intLevel > MESSAGE_UNIT_INTERRUPT_BASE))        return (ERROR);    /* If ISA interrupt level, call the IBC driver disable routine, */    if ( IS_ISA_INTERRUPT_LEVEL(intLevel) )        sysIbcIntEnable( intLevel );     /* else, it is an MPIC interrupt level */    else    	{    	enable.regAddr = getEpicVecAddr(intLevel);    	if (enable.regAddr > 0)            {            /* read the vector register */            enable.regVal = sysPciInLong((UINT32)(enable.regAddr));            /* enable the interrupt */            enable.regVal &= (~INT_MASK_BIT);            /* write the contents of the vector register back */            sysPciOutLong((UINT32)(enable.regAddr), enable.regVal);            }        }    return (OK);    }/******************************************************************************** sysEpicIntDisable - disable an Epic interrupt level** This routine disables a specified Epic interrupt level.** RETURNS: OK or ERROR if interrupt level not supported*/LOCAL int sysEpicIntDisable    (    int intLevel        /* interrupt level to disable */    )    {    LOCAL_INT_DATA      disable;     /*     * if the int. level is not for ISA or MPIC, then it is not supported.     * If not supported, just return.     */    if ((intLevel < EPIC_INTERRUPT_BASE) 		|| (intLevel > MESSAGE_UNIT_INTERRUPT_BASE))        return (ERROR);    /* If ISA interrupt level, call the IBC driver disable routine, */    if ( IS_ISA_INTERRUPT_LEVEL(intLevel) )        sysIbcIntDisable( intLevel );     /* else, it is an MPIC interrupt level */    else    	{    	/* get the vector reg. offset value */    	disable.regAddr = getEpicVecAddr(intLevel);     	if (disable.regAddr > 0)            {            /* read the vector register */            disable.regVal = sysPciInLong((UINT32)(disable.regAddr));            /* disable the interrupt */            disable.regVal |= INT_MASK_BIT;            /* write the contents of the vector register back */            sysPciOutLong((UINT32)(disable.regAddr), disable.regVal);            }	}    return (OK);    }/******************************************************************************** sysEpicIntHandler - handle an interrupt received at the Epic* * This routine will process interrupts received from PCI or ISA devices as* these interrupts arrive via the EPIC.  This routine supports EPIC interrupt* nesting.** RETURNS: N/A*/void sysEpicIntHandler     (    void    )    {    INT_HANDLER_DESC *  currHandler;    UINT32		vecNum;    int			dontCare;    /* get the vector from the EPIC IACK reg. */    vecNum = sysPciInLong((UINT32)EPIC_IACK_REG);    /*      * The purpose of the following "dummy read" is to inject      * a processor-bus dependent delay between the IACK and      * the enabling of processor interrupts. The reason this      * delay is required is due to a feature of the MPC107:     * The MPC107 asserts TA (transfer acknowledge) on the      * above IACK register read (which allows the processor to      * continue execution)  BEFORE it deasserts the interrupt to      * the processor.  A fast processor (400MHz and up) will thus     * reach the code which enables interrupts (CPU_INT_UNLOCK -      * see below) before the MPC107 has had time to deassert the      * interrupt. The effect will be a spurious interrupt which      * tags along just behind the legitimate interrupt which this      * function is currently processing.     */    (void)sysPciInLong((UINT32)EPIC_EOI_REG);    vecNum &= VECTOR_MASK;    /* Check for spurious interrupt. */    if (vecNum == 0xFF)        {        logMsg ("EPIC Spurious Interrupt!\n", 0,0,0,0,0,0);        return;        }    /*     * Allow maskable interrupts to the CPU.  EPIC will hold off     * lower and equal interrupts until EPIC_EOI is performed.     */    CPU_INT_UNLOCK(_PPC_MSR_EE);#ifdef INCLUDE_INSTRUMENTATION    if (evtLogTIsOn)      (* _func_evtLogT1_noTS) (EVENT_INT_ENT((int)vecNum),			       evtTimeStamp);#endif /* INCLUDE_INSTRUMENTATION */    /* call the necessary interrupt handlers */    if ((currHandler = sysIntTbl[vecNum]) == NULL)        {        logMsg ("uninitialized EPIC interrupt %d\r\n", vecNum, 0,0,0,0,0);        }    else        {        /* Call EACH respective chained interrupt handler */        while (currHandler != NULL)            {            currHandler->vec (currHandler->arg);            currHandler = currHandler->next;            }        }    /* Disable external interrupts. */    CPU_INT_LOCK(&dontCare);    /* Issue an end-of-interrupt to the EPIC */    sysPciOutLong((UINT32)EPIC_EOI_REG, 0);    return;    }/******************************************************************************** getEpicVecAddr - get the vector address of an EPIC register ** This routine returns the appropriate EPIC register address based on the* specified EPIC interrupt level.** RETURNS: EPIC register address or zero if not a supported level.*/LOCAL int getEpicVecAddr    (    int		intLevel	/* interrupt level to translate */    )     {    int 	offset = 0;    /* check for a timer interrupt level */    if ((intLevel >= TIMER_INTERRUPT_BASE) &&         (intLevel < INTERNAL_INTERRUPT_BASE))        {        offset = intLevel - TIMER_INTERRUPT_BASE;        offset = (int)EPIC_TIMER0_VEC_PRI_REG + (offset * REG_OFFSET * 4);        }    /* check for a serial interrupt level */    else if ((intLevel >= SERIAL_INTERRUPT_BASE) &&       (intLevel < TIMER_INTERRUPT_BASE))        {        offset = intLevel - SERIAL_INTERRUPT_BASE;        offset = (int)EPIC_SER_SRC0_VEC_PRI_REG + (offset * REG_OFFSET * 2);        }    /* check for internal interrupt level I2C, DMA1, DMA 2 */    else if ((intLevel >= INTERNAL_INTERRUPT_BASE) &&         (intLevel < MESSAGE_UNIT_INTERRUPT_BASE))        {        offset = intLevel - INTERNAL_INTERRUPT_BASE;        offset = (int)EPIC_I2C_INTR_VEC_SRC + (offset * REG_OFFSET * 2);        }    /* check for Message Unit interrupt level */    else if (intLevel == MESSAGE_UNIT_INTERRUPT_BASE)        {        offset = intLevel - MESSAGE_UNIT_INTERRUPT_BASE;        offset = (int)EPIC_MSG_UNIT_INTR_VEC_SRC + (offset * REG_OFFSET * 2);        }        return (offset);    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -