intr.c
来自「Windows CE 6.0 BSP for VOIPAC Board (PXA」· C语言 代码 · 共 416 行
C
416 行
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//------------------------------------------------------------------------------
//
// File: intr.c
//
// This file implements major part of interrupt module for Vr4131 SoC.
//
#include <windows.h>
#include <ceddk.h>
#include <nkintr.h>
#include <oal.h>
#include <oal_intr_mips.h>
#include <vr4131.h>
//------------------------------------------------------------------------------
//
// Globals: g_pICURegs/g_pGIURegs
//
// The global variables are storing virual address for ICU and GIU units
// for use in interrupt handling to avoid possible time consumig call to
// OALPAtoUA function.
//
static VR4131_ICU_REGS *g_pICURegs;
static VR4131_GIU_REGS *g_pGIURegs;
//------------------------------------------------------------------------------
//
// Function: OALIntrInit
//
// This function initialize Vr4131 interrupt hardware.
//
BOOL OALIntrInit()
{
BOOL rc = FALSE;
OALMSG(OAL_INTR&&OAL_FUNC, (L"+OALInterruptInit\r\n"));
// Initialize interrupt mapping
OALIntrMapInit();
// Get and save uncached virtual addresses fir ICU and GIU
g_pICURegs = OALPAtoUA(VR4131_REG_PA_ICU);
g_pGIURegs = OALPAtoUA(VR4131_REG_PA_GIU);
// Disable all interrupts on second level for GPIO
OUTREG16(&g_pICURegs->MGIUINTL, 0);
OUTREG16(&g_pICURegs->MGIUINTH, 0);
// We don't want get NMI on battery interrupt
OUTREG16(&g_pICURegs->NMI, ICU_NMIORINT);
// Mask all interrupts on first level
OUTREG16(&g_pICURegs->MSYSINT1, 0);
OUTREG16(&g_pICURegs->MSYSINT2, 0);
// Enable debug serial port interrupts
OUTREG16(&g_pICURegs->MDSIUINT, ICU_INTDSIU);
// Hook interrupts 0 to 2
if (!HookInterrupt(0, OALIntr0Handler)) {
OALMSG(OAL_ERROR, (
L"ERROR: OALIntrInit: HookInterrupt for MIPS interrupt 0 failed\r\n"
));
goto cleanUp;
}
if (!HookInterrupt(1, OALIntr1Handler)) {
OALMSG(OAL_ERROR, (
L"ERROR: OALIntrInit: HookInterrupt for MIPS interrupt 1 failed\r\n"
));
goto cleanUp;
}
if (!HookInterrupt(2, OALIntr2Handler)) {
OALMSG(OAL_ERROR, (
L"ERROR: OALIntrInit: HookInterrupt for MIPS interrupt 0 failed\r\n"
));
goto cleanUp;
}
#ifdef OAL_BSP_CALLBACKS
// Give BSP change to initialize subordinate controller
rc = BSPIntrInit();
#else
rc = TRUE;
#endif
cleanUp:
OALMSG(OAL_INTR&&OAL_FUNC, (L"-OALInterruptInit(rc = %d)\r\n", rc));
return rc;
}
//------------------------------------------------------------------------------
//
// Function: OALIntrRequestIrqs
//
// This function returns IRQ for CPU/SoC devices based on their
// physical address.
//
BOOL OALIntrRequestIrqs(DEVICE_LOCATION *pDevLoc, UINT32 *pCount, UINT32 *pIrqs)
{
BOOL rc = FALSE;
OALMSG(OAL_INTR&&OAL_FUNC, (
L"+OALIntrRequestIrqs(0x%08x->%d/%d/0x%08x/%d, 0x%08x, 0x%08x)\r\n",
pDevLoc, pDevLoc->IfcType, pDevLoc->BusNumber, pDevLoc->LogicalLoc,
pDevLoc->Pin, pCount, pIrqs
));
// This shouldn't happen
if (*pCount < 1) goto cleanUp;
#ifdef OAL_BSP_CALLBACKS
rc = BSPIntrRequestIrqs(pDevLoc, pCount, pIrqs);
#endif
cleanUp:
OALMSG(OAL_INTR&&OAL_FUNC, (L"-OALIntrRequestIrqs(rc = %d)\r\n", rc));
return rc;
}
//------------------------------------------------------------------------------
//
// Function: OALIntrEnableIrqs
//
BOOL OALIntrEnableIrqs(UINT32 count, const UINT32 *pIrqs)
{
BOOL rc = TRUE;
UINT32 irq, i;
OALMSG(OAL_INTR&&OAL_VERBOSE, (
L"+OALntrEnableIrqs(%d, 0x%08x)\r\n", count, pIrqs
));
for (i = 0; i < count; i++) {
#ifndef OAL_BSP_CALLBACKS
irq = pIrqs[i];
#else
// Give BSP chance to enable irq on subordinate interrupt controller
irq = BSPIntrEnableIrq(pIrqs[i]);
#endif
if (irq == OAL_INTR_IRQ_UNDEFINED) continue;
// Depending on IRQ number use internal or external mask register
if (irq < IRQ_RTCL2) {
// Use interrupt mask register 1
SETREG16(&g_pICURegs->MSYSINT1, 1 << irq);
} else if (irq < IRQ_GPIO0) {
// Use interrupt mask register 2
SETREG16(&g_pICURegs->MSYSINT2, 1 << (irq - IRQ_RTCL2));
} else if (irq < IRQ_GPIO16) {
// Use GPIO lower register
SETREG16(&g_pICURegs->MGIUINTL, 1 << (irq - IRQ_GPIO0));
// Clear interrupt (needed for edge level interrupts)
OUTREG16(&g_pGIURegs->GIUINTSTATL, 1 << (irq - IRQ_GPIO0));
// Enable this interrupt in primary level registers also
OUTREG16(&g_pICURegs->MSYSINT1, 1 << IRQ_GIU);
} else if (irq <= IRQ_GPIO31) {
// Use GPIO upper register
SETREG16(&g_pICURegs->MGIUINTH, 1 << (irq - IRQ_GPIO16));
// Clear interrupt (needed for edge level interrupts)
OUTREG16(&g_pGIURegs->GIUINTSTATH, 1 << (irq - IRQ_GPIO16));
// Enable this interrupt in primary level registers also
OUTREG16(&g_pICURegs->MSYSINT1, 1 << IRQ_GIU);
} else {
rc = FALSE;
}
}
OALMSG(OAL_INTR&&OAL_VERBOSE, (L"-OALIntrEnableIrqs(rc = %d)\r\n", rc));
return rc;
}
//------------------------------------------------------------------------------
//
// Function: OALIntrDisableIrqs
//
VOID OALIntrDisableIrqs(UINT32 count, const UINT32 *pIrqs)
{
UINT32 irq, i;
OALMSG(OAL_INTR&&OAL_FUNC, (
L"+OALIntrDisableIrqs(%d, 0x%08x)\r\n", count, pIrqs
));
for (i = 0; i < count; i++) {
#ifndef OAL_BSP_CALLBACKS
irq = pIrqs[i];
#else
// Give BSP chance to disable irq on subordinate interrupt controller
irq = BSPIntrDisableIrq(pIrqs[i]);
#endif
// Depending on IRQ number use internal or external mask register
if (irq < IRQ_RTCL2) {
// Use interrupt mask register 1
CLRREG16(&g_pICURegs->MSYSINT1, 1 << irq);
} else if (irq < IRQ_GPIO0) {
// Use interrupt mask register 2
CLRREG16(&g_pICURegs->MSYSINT2, 1 << (irq - IRQ_RTCL2));
} else if (irq < IRQ_GPIO16) {
// Use GPIO lower register
CLRREG16(&g_pICURegs->MGIUINTL, 1 << (irq - IRQ_GPIO0));
} else if (irq <= IRQ_GPIO31) {
// Use GPIO upper register
CLRREG16(&g_pICURegs->MGIUINTH, 1 << (irq - IRQ_GPIO16));
}
}
OALMSG(OAL_INTR&&OAL_FUNC, (L"-OALIntrDisableIrqs\r\n"));
}
//------------------------------------------------------------------------------
//
// Function: OALIntrDoneIrqs
//
VOID OALIntrDoneIrqs(UINT32 count, const UINT32 *pIrqs)
{
UINT32 irq, i;
OALMSG(OAL_INTR&&OAL_VERBOSE, (
L"+OALIntrDoneIrqs(%d, 0x%08x)\r\n", count, pIrqs
));
for (i = 0; i < count; i++) {
#ifndef OAL_BSP_CALLBACKS
irq = pIrqs[i];
#else
// Give BSP chance to finish irq on subordinate interrupt controller
irq = BSPIntrDoneIrq(pIrqs[i]);
#endif
// Depending on IRQ number use internal or external mask register
if (irq < IRQ_RTCL2) {
// Use interrupt mask register 1
SETREG16(&g_pICURegs->MSYSINT1, 1 << irq);
} else if (irq < IRQ_GPIO0) {
// Use interrupt mask register 2
SETREG16(&g_pICURegs->MSYSINT2, 1 << (irq - IRQ_RTCL2));
} else if (irq < IRQ_GPIO16) {
// Use GPIO lower register
SETREG16(&g_pICURegs->MGIUINTL, 1 << (irq - IRQ_GPIO0));
// Clear interrupt (needed for edge level interrupts)
OUTREG16(&g_pGIURegs->GIUINTSTATL, 1 << (irq - IRQ_GPIO0));
} else if (irq <= IRQ_GPIO31) {
// Use GPIO upper register
SETREG16(&g_pICURegs->MGIUINTH, 1 << (irq - IRQ_GPIO16));
// Clear interrupt (needed for edge level interrupts)
OUTREG16(&g_pGIURegs->GIUINTSTATH, 1 << (irq - IRQ_GPIO16));
}
}
OALMSG(OAL_INTR&&OAL_VERBOSE, (L"-OALIntrDoneIrqs\r\n"));
}
//------------------------------------------------------------------------------
//
// Function: OALIntr0Handler
//
// This is interrupt handler implementation for MIPS interrupt 0 on Vr4131.
// Most interrupts on this SoC is using this interrupt.
//
UINT32 OALIntr0Handler()
{
UINT32 irq = OAL_INTR_IRQ_UNDEFINED, sysIntr = SYSINTR_NOP;
UINT16 status, mask, *pICReg = NULL;
#ifdef OAL_ILTIMING
if (g_oalILT.active) g_oalILT.interrupts++;
#endif
// Get pending interrupt
if ((
status = INREG16(&g_pICURegs->SYSINT1) & INREG16(&g_pICURegs->MSYSINT1)
) != 0) {
for (mask = 1, irq = IRQ_BAT; mask != 0; mask <<= 1, irq++) {
if ((status & mask) != 0) break;
}
if (irq != IRQ_GIU) {
// Disable interrupt
pICReg = &g_pICURegs->MSYSINT1;
} else if ((
status =
INREG16(&g_pICURegs->GIUINTL) & INREG16(&g_pICURegs->MGIUINTL)
) != 0) {
for (mask = 1, irq = IRQ_GPIO0; mask != 0; mask <<= 1, irq++) {
if ((status & mask) != 0) break;
}
// Disable interrupt
pICReg = &g_pICURegs->MGIUINTL;
} else if ((
status =
INREG16(&g_pICURegs->GIUINTH) & INREG16(&g_pICURegs->MGIUINTH)
) != 0) {
for (mask = 1, irq = IRQ_GPIO16; mask != 0; mask <<= 1, irq++) {
if ((status & mask) != 0) break;
}
// Disable interrupt
pICReg = &g_pICURegs->MGIUINTH;
}
}else if ((
status = INREG16(&g_pICURegs->SYSINT2) & INREG16(&g_pICURegs->MSYSINT2)
) != 0) {
for (mask = 1, irq = IRQ_RTCL2; mask != 0; mask <<= 1, irq++) {
if ((status & mask) != 0) break;
}
// Disable interrupt
pICReg = &g_pICURegs->MSYSINT2;
}
if (pICReg) {
CLRREG16(pICReg, mask);
}
#ifdef OAL_BSP_CALLBACKS
// Give BSP chance to translate IRQ -- if there is subordinate
// interrupt controller in BSP it give chance to decode its status
// and change IRQ
irq = BSPIntrActiveIrq(irq);
#endif
// If there isn't valid IRQ leave
if (irq == OAL_INTR_IRQ_UNDEFINED) goto cleanUp;
// First find if IRQ is claimed by chain
sysIntr = NKCallIntChain((UCHAR)irq);
if (sysIntr == SYSINTR_CHAIN || !NKIsSysIntrValid(sysIntr)) {
// IRQ wasn't claimed or SYSINTR isn't valid, use static mapping
sysIntr = OALIntrTranslateIrq(irq);
}
if (SYSINTR_NOP == sysIntr) {
#ifdef OAL_BSP_CALLBACKS
BSPIntrEnableIrq (irq);
#endif
if (pICReg) {
SETREG16 (pICReg, mask);
}
}
cleanUp:
return sysIntr;
}
//------------------------------------------------------------------------------
//
// Function: OALIntr1Handler
//
// This is interrupt handler implementation for MIPS interrupt 1 on Vr4131.
// On this SoC this interrupt is assigned to IRQ_RTCL1.
//
UINT32 OALIntr1Handler()
{
UINT32 irq, sysIntr;
#ifdef OAL_ILTIMING
if (g_oalILT.active) g_oalILT.interrupts++;
#endif
// There can be only one source
irq = IRQ_RTCL1;
// First find if IRQ is claimed by chain
sysIntr = NKCallIntChain((UCHAR)irq);
if (sysIntr == SYSINTR_CHAIN || !NKIsSysIntrValid(sysIntr)) {
// IRQ wasn't claimed, use static mapping
sysIntr = OALIntrTranslateIrq(irq);
}
return sysIntr;
}
//------------------------------------------------------------------------------
//
// Function: OALIntr1Handler
//
// This is interrupt handler implementation for MIPS interrupt 1 on Vr4131.
// On this SoC this interrupt is assigned to IRQ_RTCL2.
//
UINT32 OALIntr2Handler()
{
UINT32 irq, sysIntr;
#ifdef OAL_ILTIMING
if (g_oalILT.active) g_oalILT.interrupts++;
#endif
// There can be only one source
irq = IRQ_RTCL2;
// First find if IRQ is claimed by chain
sysIntr = NKCallIntChain((UCHAR)irq);
if (sysIntr == SYSINTR_CHAIN || !NKIsSysIntrValid(sysIntr)) {
// IRQ wasn't claimed, use static mapping
sysIntr = OALIntrTranslateIrq(irq);
}
return sysIntr;
}
//------------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?