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 + -
显示快捷键?