📄 mpc107epic.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 + -