/*
 *  Copyright (c) 1996-2007 Digi International Inc., All Rights Reserved
 *
 *  This software contains proprietary and confidential information of Digi
 *  International Inc.  By accepting transfer of this copy, Recipient agrees
 *  to retain this software in confidence, to prevent disclosure to others,
 *  and to make no use of this software other than that for which it was
 *  delivered.  This is an unpublished copyrighted work of Digi International
 *  Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly
 *  prohibited.
 *
 *  Restricted Rights Legend
 *
 *  Use, duplication, or disclosure by the Government is subject to
 *  restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in
 *  Technical Data and Computer Software clause at DFARS 252.227-7031 or
 *  subparagraphs (c)(1) and (2) of the Commercial Computer Software -
 *  Restricted Rights at 48 CFR 52.227-19, as applicable.
 *
 *  Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
 *
 * Description.
 * =======================================================================
 * This file contains main interrupt handler routines.
 *
 *  BBUS_IrqHandler
 *      Invoked if the interrupt is BBUS_AGGREGATE_INTERRUPT 
 *
 *  NAIrqHandler
 *      Invoked if an interrupt is other than BBUS_AGGREGATE_INTERRUP
 *
 *  NOTE:
 *      1. Can not manual set BBUS_AGGREGATE_INTERRUPT
 *         Automatically set when a BBUS peripherial is installed
 *
 * Edit Date/Ver   Edit Description
 * ==============  ===================================================
 *
 * 08/12/05   JZW   Vantive 16653 - Update autodoc comment relative to setting up
 *                  timer ISRs
 *
 */

#include <errhndlr.h>
#include <mcreg_def.h>
#include <init.h>
#include <bbus_def.h>
#include <bbm_def.h>
#include <scm_def.h>
#include <mc_isr.h>
#include <isr_api.h>
#include "bbm_reg.h"
#include "reg_def.h"
#include "NA_ISR.h"
#include "isrPrivate.h"
#include "gpiomux_def.h"
#include "gpio.h"
#include "regs.h"
#include <powersave.h>

#define MAX_AHB_INTERRUPT_LEVELS    32
#define DISABLE_IRQ                 0x80

#if defined(NS9750) || defined(NS9360) || (PROCESSOR == ns9210) || (PROCESSOR == ns9215)
    #define FIRST_EXT_INT   28
#else
    #error Need to define FIRST_EXT_INT for new processor.
#endif

#define PROCESSOR_HAS_BBUS      (defined(NS9750) || defined(NS9360))


/*ad*
 * The interrupt service routines (ISR) API allows applications to install and 
 * remove ISRs.
 *
 * Writing ISRs under NET+OS
 *
 * The Digi International NS9750 chip supports 31 interrupts in the AHB bus.
 * The Bbus features an additional 25 interrupts.
 *
 * The hardware controls the priority of each interrupt in the AHB Bus. 
 * The order configured in the Interrupt Configuration Register sets the priority. 
 * When a specific interrupt occurs,
 * its handler is stored in the ISR address register. Its priority level is stored in 
 * the Active Interrupt Level Status register. The driver executes the interrupt handler with the
 * priority level passed as a parameter. An interrupt with a higher priority can preempt the current
 * interrupt. Once the task in the interrupt handler completes,
 * the interrupt driver automatically clears the interrupt to be reused.
 *
 *
 * The software controls the priority in the Bbus. Each device on the Bbus shares a common
 * interrupt on the AHB bus. The Bbus Aggregrate interrupt calls their interrupt.
 * When a device signals an interrupt, the hardware sets bits in the Bbus Bridge Interrupt Status register.
 * The bit indicates which device on the Bbus is signaling the event. 
 * If the device's interrupt level is not masked off, the hardware generates an IRQ
 * exception. This causes the NET+OS interrupt driver to execute. 
 * The Bbus Interrupt Handler determines which device is signaling the interrupt condition and 
 * calls the ISR that is registered to it. The ISR processes the interrupt and then returns. At this
 * point, the interrupt driver checks for more pending interrupts. If the interrupt driver finds 
 * pending interrupts, their ISRs are called as well. After all pending interrupts are processed, 
 * the NET+OS interrupt driver returns control to the application.
 *
 * Developing ISRs for NET+OS is straightforward; ISRs are coded as C routines and
 * should be defined like this:
 *  int (* @link NA_ISR_HANDLER)(void * handle);
 *
 * Application ISRs should always return 0x0.
 *
 * The isrParameter parameter is set to the value passed to naIsrInstall when the
 * ISR was installed.
 *
 * Call @link naIsrInstall to install ISRs. @link naIsrInstall takes a function pointer,
 * interrupt level, and pointer as parameters. @link naIsrInstall copies the function pointer into the
 * interrupt driver's table of ISRs and then enables interrupts for the specified
 * interrupt level. After this is done, the ISR is called whenever the interrupt
 * occurs. The pointer passed to @link naIsrInstall is also stored in an internal table and
 * passed to the ISR by the driver when it is invoked. The parameter can be used to
 * pass context information when the same ISR is used to service multiple interrupts.
 *
 * Call @link naIsrUninstall to uninstall ISRs. This function accepts an interrupt
 * level as a parameter. It disables interrupts from the device and removes the
 * function pointer from the ISR table.
 * 
 * Use the @link tx_interrupt_control kernel function to enable and disable all interrupts
 * on the chip. You can use @link naInterruptEnable and @link naInterruptDisable functions to selectively
 * disable interrupts from a single device.
 * 
 * When an ISR is called, it services the device by generating the interrupt and
 * returning as quickly as possible. The ISR does not need to do anything with the
 * chip interrupt controller because this is taken care of by the NET+OS interrupt
 * driver. However, the ISR does need to acknowledge the interrupt on the device so that the
 * device stops generating the interrupt. This is normally done by either reading a
 * register on the device or setting a particular bit in a register on the device.
 * 
 * Most RTOS APIs are not available to ISRs. Refer to the @link SystemSWServices:ThreadX section of this helpfile to verify
 * that the kernel services you want to use can be called safely from within an ISR. ISRs must not call
 * any kernel API, that is not ISR safe, or any other function that uses a kernel function that
 * is not ISR safe.
 * 
 * Memory usage
 * 
 * There is no additional memory usage when you call the ISR API.
 *
 * @note
 *			Please note: timer interrupts and ISRs should not be set up using calls 
 *          to ISR APIs directly. Instead, users should use functions (APIs) defined 
 *          in the timer drivers section of this document for defining and running 
 *          timer ISRs. Setting up a timer using ISR APIs directly can cause 
 *          timer interrupts to be called once only.
 *
 * @external
 * @category BSP:mcIsr
 * @library bsp
 * @platform all
 * @include "mc_isr.h"
 * @since 6.1
 * @overview Interrupt Service Routines
*ad*/

int NAInitIsr (void);

#define NA_ISR_FIQ          1
#define NA_ISR_IRQ          2

#define NA_ISR_ACTIVE_LOW   1 
#define NA_ISR_ACTIVE_HIGH  2

#define NA_ISR_FREE     0
#define NA_ISR_USED     1
#define NA_ISR_SETUP    2


/*
 *	ISR table entry structure
 */
typedef struct
{
    long            id;                 /* Interrupt Id */
    long            inuse;              /* Interrupt installed */
    long            isrType;            /* IRQ or FIQ */
    long            shouldInvert;            /* high or low active */
    NA_ISR_HANDLER  isrHandler;         /* Interrupt handler */
    void            *isrParameter;      /* Interrupt Id */
    long            idMask;             /* Id Bit Mask */
    int             priorityLevel;      /* Interrupt Priority */
    int             isEnabled;          /* Interrupt Enabled */
} NA_ISR_TYPE;

/*
 *	Global variables
 */

NA_ISR_TYPE     NAIsrTable[NA_MAX_INTERRUPTS];	            /* Table containing all ISR (AHB, BBUS) */

#if PROCESSOR_HAS_BBUS
    unsigned long   *bbusStatusReg1 = NA_BBM_ISR_ADDRESS;       /* address of BBUS Bridge Interrupt Status Register */
    volatile unsigned long   *bbusStatusReg2 = NA_BUM_DISR_ADDRESS;      /* address of BBUS DMA Interrupt Status Register */  
    unsigned long   *bbusEnableReg1 = NA_BBM_IER_ADDRESS;       /* address of BBUS Bridge Interrupt Enable Register */
    volatile unsigned long   *bbusEnableReg2 = NA_BUM_DIER_ADDRESS;      /* address of BBUS DMA Interrupt Enable Register */
    
    unsigned long   bbusEnableMask1 = 0;                        /* current state of BBus Bridge Interrupt Enable Register */
    unsigned long   bbusEnableMask2 = 0;                        /* current state of BBUS DMA Interrupt Enable register */
    
    static unsigned int bbusPriorityMask1[BBUS_MAX_INTERRUPTS];     /* A table containing the low longword of priority mask */
    static unsigned int bbusPriorityMask2[BBUS_MAX_INTERRUPTS];     /* A table containing the high longword of priority mask */
    static unsigned int lowerLevelMask1[BBUS_MAX_INTERRUPTS + 1];   /* A table contain a mask of lower priority then the current */
    static unsigned int lowerLevelMask2[BBUS_MAX_INTERRUPTS + 1];   /* A table contain a mask of lower priority then the current */
    static unsigned int upperLevelInterrupt[BBUS_MAX_INTERRUPTS];   /* A table of interrupts which is higher then the current */
    
    static unsigned int bbusInterruptCount = 0;                     /* The number of peripherials using the BBUS interrupt */
    static int bbusIrqHandlerCount = 0;
#endif

#if PROCESSOR_HAS_BBUS
    static unsigned int dmaInterruptCount = 0;                      /* The number of peripherials using the DMA interrupts */
#endif

static int isr_initialized = 0;
static int NAFiqIsrId = -1;

unsigned long NAFiqParam;           /* Referenced by naLiveFiqHandler */
unsigned long NAFiqIsr;             /* Referenced by naLiveFiqHandler */

#if PROCESSOR_HAS_BBUS

    int BBUS_IrqHandler (void);

#endif
#if defined (NS9360)
int BBUS_DMA_Handler (void);
#endif
/*
 * Static Function Prototypes
 */

static int naDefaultHandler (void *levelAsPointer);     /* Default int. level handler */


int NAGetIsrPriorityLevel (int id, int *priorityLevel)
{
    int i;

    for (i = 0; i < AHB_MAX_INTERRUPTS; i++)
    {
        if ((unsigned) id == NAAhbPriorityTab[i])
        {
            *priorityLevel = i;
            return (0);
        }
    }

#if PROCESSOR_HAS_BBUS
    for (i = 0; i < BBUS_MAX_INTERRUPTS; i++)
    {
        if ((unsigned) id == NABbusPriorityTab[i])
        {
            *priorityLevel = i;
            return (0);
        }
    }
#endif

    return (1);
}



/*ad*
 * This function determines whether an interrupt source should be inverted by the controller.
 * This feature is used with the Ethernet PHY interrupt.  By default, the PHY interrupt pin
 * is high active, but some PHYs need it to be low active.  This function can be used to 
 * invert the sense of the PHY interrupt to make it low active.
 *
 * @note    Although this function will also work with external interrupt, the preferred 
 *          method to invert them is to configure them that way in gpio.h.
 * 
 * @external
 * @category BSP:mcIsr
 * @since 6.2
 *
 * @param id		        The interrupt Level of external input pin.
 * @param invertSource      Invert the sense of the interrupt signal.
 *
 * @return SUCCESS			The interrupt has been setup
 * @return MC_INVALID_LEVEL	Invalid level
 *  
*ad*/
int naInterruptInvertSource(int id, BOOLEAN invertSource)
{
    int ccode = SUCCESS;
    
    if (!isr_initialized)
    {
        NAInitIsr ();
    }

    /* BBUS or DMA are not allowed to be MANUALLY set 
     * Automatically set by software when a BBUS peripheral is installed
     */
    if ((id < AHB_INTERRUPT_BASE) || (id >= AHB_INTERRUPT_END))
    {
        ccode = NA_INVALID_LEVEL;
        goto done;
    }
    
    if (NAIsrTable[id].inuse == NA_ISR_USED)
    {
        ccode = NA_INTERRUPT_IN_USE;
        goto done;
    }

    NAIsrTable[id].shouldInvert = invertSource;
    
done:

    return ccode;
}


/*ad*
 * This function sets an interrupt level to use the FIQ vector.  Only one
 * interrupt source can use the FIQ vector.  You must call this function
 * before calling naIsrInstall.
 * 
 * @external
 * @category BSP:mcIsr
 * @since 6.2
 *
 * @param id		        The interrupt Level of external input pin.
 * @param isFiq             TRUE = Fast Interrupt Request, FALSE = Normal Interrupt Request
 *
 * @return SUCCESS			The interrupt has been setup
 * @return MC_INVALID_LEVEL	Invalid level
 *  
 * @see @link isFiqValues
*ad*/
int naIsrSetFiq(int id, BOOLEAN isFiq)
{
    int ccode = SUCCESS;
    
    if (!isr_initialized)
    {
        NAInitIsr ();
    }

    /* Only AHB interrupts can be setup for FIQ.  The BBUS aggregate cannot be.
     */
    if (    (id < AHB_INTERRUPT_BASE) || (id >= AHB_INTERRUPT_END) 
#if PROCESSOR_HAS_BBUS
        || (id == BBUS_DMA_INTERRUPT)
#endif
        )
    {
        ccode = NA_INVALID_LEVEL;
        goto done;
    }
    
    if (NAIsrTable[id].priorityLevel != 0)
    { /* Only interrupt level 0 can use the FIQ */
        ccode = NA_INVALID_LEVEL;
        goto done;
    }
    
    if (NAIsrTable[id].inuse == NA_ISR_USED)
    {
        ccode = NA_INTERRUPT_IN_USE;
        goto done;
    }

    if (isFiq)
        NAIsrTable[id].isrType = NA_ISR_FIQ;
    else
        NAIsrTable[id].isrType = NA_ISR_IRQ;

done:
    return ccode;
}

void setupExternalIrq(int id)
{
    int index = id - SCM_EXTERNAL0_INTERRUPT;
    int config, lowPolarity, edgeSensitive;
    
    switch (id)
    {
        case SCM_EXTERNAL0_INTERRUPT:
            config = BSP_GPIO_MUX_IRQ_0_CONFIG;
            break;
        case SCM_EXTERNAL1_INTERRUPT:
            config = BSP_GPIO_MUX_IRQ_1_CONFIG;
            break;
        case SCM_EXTERNAL2_INTERRUPT:
            config = BSP_GPIO_MUX_IRQ_2_CONFIG;
            break;
        case SCM_EXTERNAL3_INTERRUPT:
            config = BSP_GPIO_MUX_IRQ_3_CONFIG;
            break;
        default:
            return;
    }
    
    /*
     * Polarity is inverted from what you think it should be.  Setting this field to 0
     * makes the interrupt high active or rising edge sensitive.
     */
    lowPolarity = ((config == BSP_GPIO_MUX_IRQ_ACTIVE_LOW) || (config == BSP_GPIO_MUX_IRQ_FALLING_EDGE));
    
    edgeSensitive = ((config == BSP_GPIO_MUX_IRQ_RISING_EDGE) || (config == BSP_GPIO_MUX_IRQ_FALLING_EDGE));
    narm_write_reg (NA_SCM_EICR_REG, NA_SCM_EICR_GET_ADDRESS(index), plty, lowPolarity);
    narm_write_reg (NA_SCM_EICR_REG, NA_SCM_EICR_GET_ADDRESS(index), lvedg, edgeSensitive);
}



/*ad*
 * Install an interrupt service routine (ISR).
 *
 * Call this function to install an ISR.  Once installed, the interrupt controller
 * will call the ISR whenever the device indicated by the parameter id signals that
 * it needs service.  The ISR must service the device and cause it to stop generating
 * the interrupt signal.
 *
 * This function enables the interrupt if it completes successfully.  It is possible for
 * the ISR to be called before this function returns to the caller.
 *
 * @note    NET+OS 6.2 and later supports nested interrupts.  This means that an ISR
 *          may be interrupted by a higher priority interrupt.
 * 
 * @external
 * @category BSP:mcIsr
 * @since 6.2
 *
 * @param id		        The ID of the device the ISR will service.
 * @param isrHandler        Address of routine which will service the device.
 * @param isrParameter      Value of parameter that will be passed to the ISR.
 *
 * @return SUCCESS			    The ISR has been installed and the interrupt has been enabled.
 * @return NA_INTERRUPT_IN_USE  The interrupt level is already in use.
 * @return NA_INVALID_LEVEL     The value of id is invalid.
 *  
*ad*/
int naIsrInstall(int id, NA_ISR_HANDLER isrHandler, void * isrParameter)

{
    int index;
    int ahbId=0;
    int registerAhbIsr = 0;

    unsigned long   ahbIsrHandler=0;

    if (!isr_initialized)
    {
        NAInitIsr ();
    }


    /* BBUS or DMA are not allowed to be MANUALLY set 
     * Automatically set by software when a BBUS peripheral is installed
     */
    if ((id < 0) || (id >= NA_MAX_INTERRUPTS) 
#if PROCESSOR_HAS_BBUS
        || id == BBUS_AGGREGATE_INTERRUPT
        || id == BBUS_DMA_INTERRUPT
#endif
        )

    {
        return (NA_INVALID_LEVEL);
    }

    /* Only one ISR can be installed for FIQ */
    if ((NAIsrTable[id].inuse == NA_ISR_USED)
        || ((NAIsrTable[id].isrType == NA_ISR_FIQ) && (NAFiqIsrId >= 0)))
    {
        return (NA_INTERRUPT_IN_USE);
    }

    /* NAIsrTable is indexed based on interrupt id */
    NAIsrTable[id].inuse = NA_ISR_USED;
    NAIsrTable[id].isrHandler = isrHandler;
    NAIsrTable[id].isrParameter = isrParameter;

    /* Interrupt for AHB Peripherals */
    if ((id >= AHB_INTERRUPT_BASE) && (id < AHB_INTERRUPT_END))
    {
        ahbId = id;
        ahbIsrHandler = (unsigned long)isrHandler;
        registerAhbIsr = 1;
    }  
#if PROCESSOR_HAS_BBUS      
    /* Interrupt for BBUS Peripheral */
    else if (((id >= BBUS_BRIDGE_INTERRUPT_BASE) && (id < BBUS_BRIDGE_INTERRUPT_END))
                || ((id >= BBUS_DMA_INTERRUPT_BASE) && (id < BBUS_DMA_INTERRUPT_END)))
    {
#if defined (NS9360)
      if ((id >= BBUS_DMA_INTERRUPT_BASE) && (id < BBUS_DMA_INTERRUPT_END))
	{
            /* BBUS periperals shares a common ISR on AHB bus */
            /* Enable BBUS Interrupt which controls both the BBUS Bridge and BBUS DMA */
	      /* NAIsrTable is indexed based on interrupt id */
	  

	  ahbId = BBUS_DMA_INTERRUPT;
	  if (NAIsrTable[ahbId].inuse != NA_ISR_USED)
	    {
	        ahbIsrHandler = (unsigned long)BBUS_DMA_Handler;
            NAIsrTable[ahbId].inuse = NA_ISR_USED;
            NAIsrTable[ahbId].isrHandler = (NA_ISR_HANDLER) BBUS_DMA_Handler;
            NAIsrTable[ahbId].isrParameter = isrParameter;
		/* To do */
		/* We have to enable the corresponding DMA here */
		
	    }
	    else
		goto done;
	    registerAhbIsr = 1;
	    
      }
      else
#endif
         /* Any Bbus peripheral installed */
        if (bbusInterruptCount == 0)
        {
            /* BBUS periperals shares a common ISR on AHB bus */
            /* Enable BBUS Interrupt which controls both the BBUS Bridge and BBUS DMA */
            ahbId = BBUS_AGGREGATE_INTERRUPT;
            ahbIsrHandler = (unsigned long)BBUS_IrqHandler;
            registerAhbIsr = 1;
        }
    }    
#endif
    else
    {
        return (NA_INVALID_LEVEL);
    }

    if (!registerAhbIsr)
    {
        goto done;
    }

    index = NAIsrTable[ahbId].priorityLevel;
    NASetInterruptID (index, ahbId);

/*    if (isrType & NA_FLAG_FAST_IRQ) */
    if (NAIsrTable[ahbId].isrType == NA_ISR_FIQ)
    {
        NAFiqParam = (unsigned long) isrParameter;
        NAFiqIsr = (unsigned long) ahbIsrHandler;
        NASetInterruptType (index, SCM_ICR_FIRQ);
        NAIsrTable[ahbId].isrType = NA_ISR_FIQ; 
        NASetInterruptVectorAddress  (index, 0);
        NASetFiqVectorAddress ((unsigned long) naLiveFiqHandler);
        NAFiqIsrId = id;
    }
    else
    {
        NASetInterruptVectorAddress  (index, ahbIsrHandler);
        NASetInterruptType (index, SCM_ICR_IRQ);
        NAIsrTable[ahbId].isrType = NA_ISR_IRQ; 
    }

    if ((ahbId == SCM_EXTERNAL0_INTERRUPT) || 
        (ahbId == SCM_EXTERNAL1_INTERRUPT) || 
        (ahbId == SCM_EXTERNAL2_INTERRUPT) || 
        (ahbId == SCM_EXTERNAL3_INTERRUPT))
    {
        setupExternalIrq(ahbId);
    }

/*    if (isrFlag & NA_FLAG_INVERT_SIGNAL) */
    if ((NAIsrTable[ahbId].shouldInvert))
    {
        NASetInterruptSignalLevel (index, SCM_ICR_ACTIVE_LOW);
    }
    else
    {
        NASetInterruptSignalLevel (index, SCM_ICR_ACTIVE_HIGH);
    }

done:
    /* Enable Interrupts */
    
    naInterruptEnable (id);
        
    return (SUCCESS);
}



/*ad*
 * Uninstall an interrupt service routine (ISR).
 *
 * Call this function to uninstall an ISR.  The interrupt level will be disabled.
 *
 * @external
 * @category BSP:mcIsr
 * @since 6.2
 *
 * @param id		        The ID of the interrupt to disable.
 *
 * @return SUCCESS			    The ISR has been installed and the interrupt has been enabled.
 * @return NA_INVALID_STATE     The ISR handler has not been initialized.
 * @return NA_INVALID_LEVEL     The value of id is invalid or there is no ISR installed for it.
 *  
*ad*/
int naIsrUninstall(int id)
{
    int index;
    int ahbId = 0;

    int deregisterAhbIsr = 0;

    if (!isr_initialized)
    {
        return (NA_INVALID_STATE);
    }

    /* Not allowed to MANUALLY set BBUS or DMA
     * Automatically set when a BBUS peripheral is installed
     */
    if ((id < 0) || (id >= NA_MAX_INTERRUPTS) 
#if PROCESSOR_HAS_BBUS
        || id == BBUS_DMA_INTERRUPT
        || id == BBUS_AGGREGATE_INTERRUPT
#endif
        )
    {
        return (NA_INVALID_LEVEL);
    }

    if ((NAIsrTable[id].inuse != NA_ISR_USED))
    {
        return (SUCCESS);
    }

    NAIsrTable[id].isrHandler = naDefaultHandler;

    /* Interrupt for AHB Peripherals */
    if ((id >= AHB_INTERRUPT_BASE) && (id < AHB_INTERRUPT_END))
    {
        ahbId = id;
        deregisterAhbIsr = 1;
    }

#if PROCESSOR_HAS_BBUS
    /* Interrupt for BBUS Peripheral */
    else if (((id >= BBUS_BRIDGE_INTERRUPT_BASE) && (id < BBUS_BRIDGE_INTERRUPT_END))
                || ((id >= BBUS_DMA_INTERRUPT_BASE) && (id < BBUS_DMA_INTERRUPT_END)))
    {
        /* Last Bbus peripheral to be disabled */
        if (bbusInterruptCount == 1)
        {
            /* Disable BBUS from AHB Bus Interrupt */
            ahbId = BBUS_AGGREGATE_INTERRUPT;
            deregisterAhbIsr = 1;

            /* Disable main bbus interrupt in BBUS Bridge Module */
            narm_write_reg(NA_BBM_IER, NA_BBM_IER_ADDRESS, glbl, BBM_DISABLE);
        }
    }
#endif
    else
    {
        return (NA_INVALID_LEVEL);
    }
    
    if (!deregisterAhbIsr)
    {
        goto done;
    }

    index = NAIsrTable[ahbId].priorityLevel;

    if (NAIsrTable[index].isrType == NA_ISR_IRQ)
    {
        NASetInterruptVectorAddress  (index, (unsigned long) naDefaultHandler);
    }
    else
    {
        /* FIQ */
        NASetInterruptType (index, SCM_ICR_IRQ);
        NASetFiqVectorAddress ((unsigned long)FIQ_Handler);
        NAFiqIsrId = -1;
    }

done:

    /* Disable Interrupts */
    naInterruptDisable (id);
    NAIsrTable[id].inuse = NA_ISR_FREE;

    return (SUCCESS);
}

/*
 *  Function:       int naMaskLowerLevelsInAhbBus (int level)
 *
 *  Description:
 *
 *      This function disables all interrupts which are less than or equal to
 *      the specified level. This will allow only interrupt with higher
 *      levels in the AHB bus to interrupt the current interrupt service routine.
 *
 *  Parameter:
 *
 *      level               the interrupt level number
 *
 *  Return Values:
 *
 *      NA_INVALID_LEVEL
 *      SUCCESS
 *
 */

static int naMaskLowerLevelsInAhbBus (unsigned int level)
{
    int irqLevel = level;
    WORD32 const masks[] = {0x7f7f7f7f, 0xff7f7f7f, 0xffff7f7f, 0xffffff7f};
        
    if (irqLevel > 31)
    {
        return (NA_INVALID_LEVEL);
    }

    do
    {
        *ICR_getAddress(irqLevel) = *ICR_getAddress(irqLevel) & masks[irqLevel & 3];
        irqLevel = (irqLevel & 0x1c) + 4;
    } while (irqLevel < AHB_MAX_INTERRUPTS);

    return (SUCCESS);
}


/*
 *  Function:       int naUnmaskLowerLevelsInAhbBus (int level)
 *
 *  Description:
 *
 *      This function enable all interrupts which are less than or equal to
 *      the specified level. This will allow only interrupt with higher
 *      levels in the AHB bus to interrupt the current interrupt service routine.
 *
 *  Parameter:
 *
 *      level               the interrupt level number

 *
 *  Return Values:
 *
 *      NA_INVALID_LEVEL
 *      SUCCESS
 *
 */

static int naUnmaskLowerLevelsInAhbBus (unsigned int level)
{
    int controlIndex;
    int irqLevel = level;
    WORD32 const masks[] = {0xffffffff, 0x7fffffff, 0x7f7fffff, 0x7f7f7fff};
        
    if (irqLevel > 31)
    {
        return (NA_INVALID_LEVEL);
    }


    controlIndex = irqLevel >> 2;
    do
    {
        *ICR_getAddress(irqLevel) = *ICR_getAddress(irqLevel) | (masks[irqLevel & 3] & NAirqEnableOrWord[controlIndex]);
        controlIndex++;
        irqLevel = controlIndex << 2;
    } while (irqLevel < AHB_MAX_INTERRUPTS);
            
    return (SUCCESS);
}

#if PROCESSOR_HAS_BBUS

/*
 *  Function:       int naMaskLowerLevelsInBbus (int level, unsigned long bitMask1, unsigned long bitMask2)
 *
 *  Description:
 *
 *      This function disables all interrupts which are less than or equal to
 *      the specified level. This will allow only interrupt with higher
 *      levels to interrupt the current interrupt service routine.
 *
 *  Parameter:
 *
 *      level               the interrupt level number
 *      bit_mask            bit Mask
 *
 *  Return Values:
 *
 *      NA_INVALID_LEVEL
 *      SUCCESS
 *
 */

static int naMaskLowerLevelsInBbus (unsigned int level, unsigned long bitMask1, unsigned long bitMask2)
{
    unsigned long mask;
        
    if (level < (BBUS_MAX_INTERRUPTS + 1))
    {
        /*  bit mask 1 */
        mask = lowerLevelMask1[level] & bitMask1;
        mask &= bbusEnableMask1;
        (*bbusEnableReg1) = mask;

        /* bit mask 2 */
        mask = lowerLevelMask2[level] & bitMask2;
        mask &= bbusEnableMask2;
        (*bbusEnableReg2) = mask;
        return (0);
    }

    return (NA_INVALID_LEVEL);
}
#endif


/*ad*
 * Enable an interrupt level.
 *
 * Call this function to enable interrupts from the device specified by the parameter id.
 *
 * It is possible the interrupt will occur before this function returns.
 *
 * @external
 * @category BSP:mcIsr
 * @since 6.2
 *
 * @param id		        The ID of the interrupt to enable.
 *
 * @return SUCCESS			    The interrupt level has been enabled.
 * @return NA_INVALID_STATE     The ISR handler has not been initialized.
 * @return NA_INVALID_LEVEL     The value of id is invalid.
 *  
*ad*/
int naInterruptEnable(int id)
{
    int index;

    if (!isr_initialized)
    {
        return (NA_INVALID_STATE);
    }

    if ((id < 0) || (id > NA_MAX_INTERRUPTS)
#if PROCESSOR_HAS_BBUS
#if defined (NS9750)
	 || id == BBUS_DMA_INTERRUPT
#endif
        || id == BBUS_AGGREGATE_INTERRUPT
#endif
        )
    {
        return (NA_INVALID_LEVEL);
    }
    /* In NS9360, when we install the BBUS DMA, we have to enable the
       Interrupt vector for the BBUS DMA Interrupt in the SCM module.
    */

#if defined (NS9360)    
    if ((id >= BBUS_DMA_INTERRUPT_BASE) && (id < BBUS_DMA_INTERRUPT_END))
    {
        index = NAIsrTable[BBUS_DMA_INTERRUPT].priorityLevel;
        NASetInterruptEnable (index, SCM_ICR_ENABLE);
    }
#endif
    /* Enable the AHB peripheral interrupts - System Control Module */
    if ((id >= AHB_INTERRUPT_BASE) && (id < AHB_INTERRUPT_END))
    {
        index = NAIsrTable[id].priorityLevel;

#if PROCESSOR_HAS_BBUS
        /* If ISR with lower priority is enabled during an AHB Bbus Interrupt, then ISR is masked.
           Once BBUS has completed, then interrupts will be enabled in the ICR register */
        if (bbusIrqHandlerCount == 0 || (bbusIrqHandlerCount && (index > NAIsrTable[BBUS_AGGREGATE_INTERRUPT].priorityLevel)))
        {
            NASetInterruptEnable (index, SCM_ICR_ENABLE);
        }
#else
        NASetInterruptEnable (index, SCM_ICR_ENABLE);
#endif
        NAIsrTable[id].isEnabled = 1;
        
        return (SUCCESS);
    }

#if PROCESSOR_HAS_BBUS

    /*
     * Enables the specified interrupt bit in these registers:
     *
     *      BBUS Bridge
     *          Module:     BBUS Bridge Module
     *          Register:   BBUS Bridge Enable Register
     *
     *      BBUS DMA
     *          Module:     BBUS Utility Module
     *          Register:   BBUS DMA Enable Register
     *
     * The current state of the register is stored in 
     *          bbusEnableMask1   - BBUS Bridge
     *          bbusEnableMask2  - BBUS DMA
     */

    /* BBUS Bridge Peripheral */
    if ((id >= BBUS_BRIDGE_INTERRUPT_BASE) && (id < BBUS_BRIDGE_INTERRUPT_END))
    {
        index = getBbusBridgeIndex (id);
        NASetPeriphBbusInterruptEnable (index, SCM_ICR_ENABLE);
        bbusEnableMask1 |= NAIsrTable[id].idMask;
        bbusInterruptCount++;
    }

   /* BBUS DMA  */
    else if ((id >= BBUS_DMA_INTERRUPT_BASE) && (id < BBUS_DMA_INTERRUPT_END))
    {
        /* Enable individual DMA interrupt in BBUS DMA */
        index = getBbusDmaIndex (id);
        NASetDmaBbusInterruptEnable (index, SCM_ICR_ENABLE);
        bbusEnableMask2 |= NAIsrTable[id].idMask;
#if defined (NS9750)
        /* Enable DMA Interrupt bit field in BBUS Bridge Enable Reg which is shared by all DMAs */
        if (++dmaInterruptCount == 1)
        {
            index = getBbusBridgeIndex (BBUS_DMA_INTERRUPT);
            NASetPeriphBbusInterruptEnable (index, SCM_ICR_ENABLE);
            bbusEnableMask1 |= NAIsrTable[BBUS_DMA_INTERRUPT].idMask;
            bbusInterruptCount++;
        }
#else
    return (SUCCESS);
#endif
	
    }
    else
    {
        return (NA_INVALID_LEVEL);
    }

    if (bbusInterruptCount == 1)
    {
        /* Enable main bbus interrupt in BBUS Bridge Module */
        narm_write_reg(NA_BBM_IER, NA_BBM_IER_ADDRESS, glbl, BBM_ENABLE);
        bbusEnableMask1 |= BBM_IER_GLOBAL_MASK;

        /* Enable BBUS Interrupt bit field in System Control Module Interrupt Config Reg */
        index = NAIsrTable[BBUS_AGGREGATE_INTERRUPT].priorityLevel;
        NASetInterruptEnable (index, SCM_ICR_ENABLE);
    }

    naMaskLowerLevelsInBbus (0, bbusEnableMask1, bbusEnableMask2);

    return (SUCCESS);
#else
    return (NA_INVALID_LEVEL);
#endif
}

/*ad*
 * Disable an interrupt level.
 *
 * Call this function to disable interrupts from the device specified by the parameter id.
 *
 * @external
 * @category BSP:mcIsr
 * @since 6.2
 *
 * @param id		        The ID of the interrupt to disable.
 *
 * @return SUCCESS			    The interrupt level has been disabled.
 * @return NA_INVALID_STATE     The ISR handler has not been initialized.
 * @return NA_INVALID_LEVEL     The value of id is invalid.
 *  
*ad*/
int naInterruptDisable(int id)
{
    int index;

    if (!isr_initialized)
    {
        return (NA_INVALID_STATE);
    }

    if ((id < 0) || (id > NA_MAX_INTERRUPTS)
#if PROCESSOR_HAS_BBUS
        || id == BBUS_DMA_INTERRUPT
        || id == BBUS_AGGREGATE_INTERRUPT
#endif
        )
    {
        return (NA_INVALID_LEVEL);
    }

    /* Disable the interrupts for peripheral on the AHB */
    if ((id >= AHB_INTERRUPT_BASE) && (id < AHB_INTERRUPT_END))
    {
        index = NAIsrTable[id].priorityLevel;
        NASetInterruptEnable (index, SCM_ICR_DISABLE);
        NAIsrTable[id].isEnabled = 0;
        return (SUCCESS);
    }

#if PROCESSOR_HAS_BBUS

    /*
     * Disables the specified interrupt bit in these registers:
     *
     *      BBUS Bridge
     *          Module:     BBUS Bridge Module
     *          Register:   BBUS Bridge Enable Register
     *
     *      BBUS DMA
     *          Module:     BBUS Utility Module
     *          Register:   BBUS DMA Enable Register
     *
     * The current state of the register is stored in 
     *          bbusEnableMask1   - BBUS Bridge
     *          bbusEnableMask2  - BBUS DMA .
     */

    /* BBUS Bridge */
    if ((id >= BBUS_BRIDGE_INTERRUPT_BASE) && (id < BBUS_BRIDGE_INTERRUPT_END))
    {
        index = getBbusBridgeIndex (id);
        NASetPeriphBbusInterruptEnable (index, SCM_ICR_DISABLE);
        bbusEnableMask1 &= ~(NAIsrTable[id].idMask);
        bbusInterruptCount--;
    }

    /* BBUS DMA */
    else if (id >= BBUS_DMA_INTERRUPT_BASE && id < BBUS_DMA_INTERRUPT_END)
    {
        /* Disable individual DMA interrupt in BBUS DMA */
        index = getBbusDmaIndex (id);
        NASetDmaBbusInterruptEnable (index, SCM_ICR_DISABLE);
        bbusEnableMask2 &= ~(NAIsrTable[id].idMask);

        /* Disable DMA Interrupt bit field in BBUS Bridge Enable Reg which is shared by all DMAs */
        if (--dmaInterruptCount == 0)
        {
            index = getBbusBridgeIndex (BBUS_DMA_INTERRUPT);
            NASetPeriphBbusInterruptEnable (index, SCM_ICR_DISABLE);
            bbusEnableMask1 &= ~NAIsrTable[id].idMask;
            bbusInterruptCount--;
        }
    }
    else
    {
        return (NA_INVALID_LEVEL);
    }
        
    /* Any more Bbus interrupts */
    if (bbusInterruptCount == 0)
    {
        /* Disable main bbus interrupt in BBUS Bridge Module */
        narm_write_reg(NA_BBM_IER, NA_BBM_IER_ADDRESS, glbl, BBM_DISABLE);
        bbusEnableMask1 &= ~BBM_IER_GLOBAL_MASK;

        /* Disable BBUS interrupt in the System Control Module Interrupt Config Reg */
        index = NAIsrTable[BBUS_AGGREGATE_INTERRUPT].priorityLevel;
        NASetInterruptEnable (index, SCM_ICR_DISABLE);
    }

    naMaskLowerLevelsInBbus (0, bbusEnableMask1, bbusEnableMask2);
    return (SUCCESS);
#else
    return NA_INVALID_LEVEL;
#endif
}


#if PROCESSOR_HAS_BBUS

/*
 *  Function:       int naGetInterruptLevelInBbus (void)
 *
 *  Description:
 *
 *      This function checks the which interrupt is enabled in the Interrupt
 *      Status Register. The function will return the
 *      first interrupt set starting from high to low priority.
 *      The BBUS DMA bit in BBUS DMA is not examine because it is taken care of
 *      
 *
 *          Status register (2 longwords = 64 bit)
 *
 *              statusReg1    BUS Bridge Interrupt Status Register
 *              statusReg2   BBUS DMA Interrupt Status Register
 *                  
 *          Priority mask   (2 longwords = 64 bit)
 *
 *              bbusPriorityMask1    BBUS Bridge Priority Mask
 *              bbusPriorityMask2   BBUS DMA Priority Mask
 *
 *  Parameter:
 *
 *      None
 *
 *  Return Values:
 *
 *      NA_INTERRUPT_NOT_PENDING	no interrupt is pending
 *      > 0							level of highest pending interrupt
 *
 */

static int naGetInterruptLevelInBbus (void)
{
    unsigned long statusReg1 = *bbusStatusReg1 & *bbusEnableReg1 & 0xfffffffe;
    unsigned long statusReg2 = *bbusStatusReg2 & *bbusEnableReg2;
    int setsize = 32; /* Half the number of priorities, power of 2 */
    int index = 32; /* Also start at half-size */
    
    /*  instead of a brute force while loop -- use a binary 
        search method and converge in order (log n) time 
        versus order (n) time    
    */

    /* Verify that we have an interrupt to process */
    if (!( statusReg1 & bbusPriorityMask1[0] 
	   || statusReg2 & bbusPriorityMask2[0]) )
    {
      return NA_INTERRUPT_NOT_PENDING;
    }

    while (setsize != 1) {
      setsize >>= 1; /* Divide by two */
      if (statusReg1 & bbusPriorityMask1[index] 
	  || statusReg2 & bbusPriorityMask2[index])
	{
	  /* Search higher */
	  index += setsize;
	} else {
	  /* Search lower */
	  index -= setsize;
	}
    }
    if (statusReg1 & bbusPriorityMask1[index] 
	|| statusReg2 & bbusPriorityMask2[index])
      {
	/* Here's the one */
	return NABbusPriorityTab[index];
      } else {
	/* Down one more */
	return NABbusPriorityTab[index - 1];
      }
}
#endif

/*
 *  Function:   int naDefaultHandler (void *levelAsPointer)
 *
 *  Description:
 *
 *      This function is used as the default interrupt handler for those
 *      interrupts which does not have one installed.
 *
 *  Parameter:
 *
 *      levelAsPointer      contain the interrupt level value
 *                              level = (int) levelAsPoiner
 *
 *  Return Values:
 *
 *      SUCCESS
 */

static int naDefaultHandler (void *levelAsPointer)

{
    int bitnum = (int) levelAsPointer;

    naInterruptDisable (bitnum);
    return (0);
}

#if PROCESSOR_HAS_BBUS

/*
 *  Function:   int BBUS_IrqHandler (void)
 *
 *  Description:
 *
 *      This function is the Interrupt dispatch routine to handle the BBUS
 *      Invoked if the interrupt is BBUS_AGGREGATE_INTERRUPT
 *      This Interrupt is under supervisor mode.
 *
 *      It's main function is as follows
 *
 *          1. Get the current interrupt to be processed from high to low
 *             priority by reading (ISRE)
 *          2. Disable interrupt defined in NAIrqMask which are equal and
 *             lower than the current interrupt in the (IER)
 *          3. Enable IRQ in CPSR so interrupts with higher level can interrupt
 *             the current interrupt
 *          4. Process the current interrupt handler
 *          5. Disable IRQ in CPSR so no interrupt can occur
 *          6. Enable all interrupt level in the (IER) defined in NAIrqMask
 *
 *
 *  Parameter:
 *
 *      None
 *
 *  Return Values:
 *
 *      SUCCESS
 */

#if defined (NS9360)

int BBUS_DMA_Handler (void)
{
    unsigned long   level;
    int             dmaChannel = 0;

    /* Clear the Interrupt to reenable bbus */

    /* *NC_SCM_ISRR_ADDRESS = 0; */ /* This has been done by the 
        NAIrqHandler() */

    level = *NA_BUM_DISR_ADDRESS;   /* read the BBUS DMA Interrupt Status */
    level &= *NA_BUM_DIER_ADDRESS;  /* mask off disabled interrupts */
    
    if (level & NA_BBUS_INTERRUPT_DMA_CH0TO7)
    {
        if (level & NA_BBUS_INTERRUPT_DMA_CH0TO3)
        {
            if (level & NA_BBUS_INTERRUPT_DMA_CH0TO1)
            {
                if (level & NA_BBUS_INTERRUPT_DMA_CH0)
                    dmaChannel = 0;
                else 
                    dmaChannel = 1;
            }
            else
            {
                if (level & NA_BBUS_INTERRUPT_DMA_CH2)
                    dmaChannel = 2;
                else 
                    dmaChannel = 3;
            }
        }
        else if (level & NA_BBUS_INTERRUPT_DMA_CH4TO7)
        {
            if (level & NA_BBUS_INTERRUPT_DMA_CH4TO5)
            {
                if (level & NA_BBUS_INTERRUPT_DMA_CH4)
                    dmaChannel = 4;
                else 
                    dmaChannel = 5;
            }
            else
            {
                if (level & NA_BBUS_INTERRUPT_DMA_CH6)
                    dmaChannel = 6;
                else 
                    dmaChannel = 7;
            }
        }
    }
    else if (level & NA_BBUS_INTERRUPT_DMA_CH8TO15)
    {
        if (level & NA_BBUS_INTERRUPT_DMA_CH8TO11)
        {
            if (level & NA_BBUS_INTERRUPT_DMA_CH8TO9)
            {
                if (level & NA_BBUS_INTERRUPT_DMA_CH8)
                    dmaChannel = 8;
                else 
                    dmaChannel = 9;
            }
            else 
            {
                if (level & NA_BBUS_INTERRUPT_DMA_CH10)
                    dmaChannel = 10;
                else 
                    dmaChannel = 11;
            }
        }
        else if (level & NA_BBUS_INTERRUPT_DMA_CH12TO15)
        {
            if (level & NA_BBUS_INTERRUPT_DMA_CH12TO13)
            {
                if (level & NA_BBUS_INTERRUPT_DMA_CH12)
                    dmaChannel = 12;
                else 
                    dmaChannel = 13;
            }
            else 
            {
                if (level & NA_BBUS_INTERRUPT_DMA_CH14)
                    dmaChannel = 14;
                else 
                    dmaChannel = 15;
            }
        }
    }
   
    ((NA_ISR_HANDLER)NAIsrTable[dmaChannel+BBUS_DMA_INTERRUPT_BASE].isrHandler)(NAIsrTable[dmaChannel+BBUS_DMA_INTERRUPT_BASE].isrParameter);

    return (0);
}

#endif

/*
 *  Function:   int BBUS_IrqHandler (void)
 *
 *  Description:
 *
 *      This function is the Interrupt dispatch routine to handle the BBUS
 *      Invoked if the interrupt is BBUS_AGGREGATE_INTERRUPT
 *      This Interrupt is under supervisor mode.
 *
 *      It's main function is as follows
 *
 *          1. Get the current interrupt to be processed from high to low
 *             priority by reading (ISRE)
 *          2. Disable interrupt defined in NAIrqMask which are equal and
 *             lower than the current interrupt in the (IER)
 *          3. Enable IRQ in CPSR so interrupts with higher level can interrupt
 *             the current interrupt
 *          4. Process the current interrupt handler
 *          5. Disable IRQ in CPSR so no interrupt can occur
 *          6. Enable all interrupt level in the (IER) defined in NAIrqMask
 *
 *
 *  Parameter:
 *
 *      None
 *
 *  Return Values:
 *
 *      SUCCESS
 */


int BBUS_IrqHandler (void)
{
    int             level;
    int             bbusLevel;
    int             bbusIndex;
    
    unsigned long   curLevelMask1;
    unsigned long   curLevelMask2;

    /* Clear the Interrupt to reenable bbus */

    /* *NC_SCM_ISRR_ADDRESS = 0; */ /* This has been done by the 
        NAIrqHandler() */


    bbusLevel = NAIsrTable[BBUS_AGGREGATE_INTERRUPT].priorityLevel;
    if (bbusIrqHandlerCount == 0)
    {
        naMaskLowerLevelsInAhbBus (bbusLevel + 1);
    }

    bbusIrqHandlerCount++;

    /* 
     * BBus Interrupt is shared by multiple devices on the BBUS
     *      curLevelMask1     BBUS Bridge Interrupt Enable Register
     *      curLevelMask2    BBUS DMA Interrupt Enable Register
     *
     */

    curLevelMask1 = (*bbusEnableReg1);
    curLevelMask2 = (*bbusEnableReg2);

    /* Return level of highest pending interrupt in (*interruptStatusReg) */
    level = naGetInterruptLevelInBbus ();        

    while (level >= 0)
    {
        bbusIndex =  getBbusIndex (level);

        /* disable peripheral interrupts which are equal or lower */
        naMaskLowerLevelsInBbus (upperLevelInterrupt[bbusIndex], curLevelMask1, curLevelMask2);

        /* enable IRQ interrupt */
        NASetIRQ (IRQ_ENABLED);

        /* Process interrupt handler */
        ((NA_ISR_HANDLER)NAIsrTable[level].isrHandler)(NAIsrTable[level].isrParameter);

        /* disable IRQ interrupt */
        NASetIRQ (IRQ_DISABLED);

        /* enable peripheral interrupts back to current level */
        naMaskLowerLevelsInBbus (0, curLevelMask1, curLevelMask2);

        /* get the next highest pending interrupt */
        level = naGetInterruptLevelInBbus ();
    }

    /* Enable Lower priority only if bbus ISR is completed */
    bbusIrqHandlerCount--;  
    if (bbusIrqHandlerCount == 0)
    {
        naUnmaskLowerLevelsInAhbBus (bbusLevel + 1);
    }

    return (0);
}

#endif /* PROCESSOR_HAS_BBUS*/


/*
 *  Function:   int NAIrqHandler (void)
 *
 *  Description:
 *
 *      This function is the Interrupt dispatch routine to handle all IRQ interrupts.
 *
 *      It's main function is as follows
 *
 *          1. Get the current interrupt from the Interrupt Vector Address Register
 *          2. Process the current interrupt handle
 *          3. Clear the interrupt
 *
 *
 *  Parameter:
 *
 *      None
 *
 *  Return Values:
 *
 *      SUCCESS
 */
#if (PROCESSOR == ns9210) || (PROCESSOR == ns9215)
int justRead;
#endif

int NAIrqHandler (void)
{
    long    interruptId;
    long    interruptLevel;
    static long savedLevel[MAX_AHB_INTERRUPT_LEVELS];
    static int  savedLevelIndex = 0;
    NA_ISR_HANDLER  isrHandler;
    
    TX_INTERRUPT_SAVE_AREA;
    
    /* The interrupt invoked is stored in interrupt vector register*/

#if !(PROCESSOR == ns9210) && !(PROCESSOR == ns9215)
    /*
     * In the NS9360 and NS9750 chips, both FIQ and IRQ interrupts update the
     * ISRADDRESS register at 0xa0900164.  It is possible for the IRQ routine 
     * to read the ISRADDR register, get zero, then for an FIQ to occur and 
     * cause the ISRADDR register to be updated, and then for the IRQ routine to
     * try reading it again and get zero again.  To deal with this, we need to
     * disable the device generating FIQ interrupts while we are trying to read
     * the ISRADDR register.  This device should always be interrupt level 0, so
     * we can disable it by disabling interrupt level 0.  Note that disabling the
     * FIQ by setting the FIQ bit in the CPSR doesn't do the job because the device
     * assigned to the FIQ will still be generating an interrupt and perturbing the
     * hardware behind the scenes.
     *
     * Note that although FIQ must be assigned to interrupt level zero, the interrupt
     * level 0 device does not necessarily need to use FIQ.  So we may be disabling
     * this device when we don't really need to.  However, checking would probably
     * waste more time than just doing it....
     */
#define ENABLE_LEVEL_0_INTERRUPT        (0x80000000)

    *NA_SCM_ICR00_ADDRESS &= ~ENABLE_LEVEL_0_INTERRUPT;      /* disable FIQ interrupts */
#else
    /*
     * The write to the ISADDR register to clear and re-enable the interrupt level being serviced 
     * requires two clock cycles to complete. There is protection in hardware that inserts one clock 
     * cycle between a write followed a read to the same address. However, this register is unique in 
     * that it requires two clock cycles. With buffering enabled for internal ASIC register accesses, the 
     * write to the ISADDR register was pushed to immediately before the read to ISADDR. Even though 
     * hardware inserted a one cycle wait state, the write actually required two cycles. 
 
     * The work around is that before the read to the ISADDR register, perform a bogus write or read to 
     * any other internal ASIC register to consume an extra clock cycle. Make sure that the bogus access 
     * is not optimized away.
     *
     * The General Arbiter Control register at 0xA0900000 is always safe to read.
     */
#define A_ASIC_REG  (volatile unsigned long *) 0xA0900000
        justRead  = *A_ASIC_REG;
#endif
    isrHandler = (NA_ISR_HANDLER) narm_read_reg(NA_SCM_ISRR_REG, NA_SCM_ISRR_ADDRESS, address);

#if !(PROCESSOR == ns9210) && !(PROCESSOR == ns9215)
    if (isrHandler == 0)     /* This should not happen */
    { 
      /* It is possible when FIQ and IRQ are enabled, FIQ handler can
	 cause the ISADDR register to be invalid, so read again. */
        isrHandler = (NA_ISR_HANDLER) narm_read_reg(NA_SCM_ISRR_REG, NA_SCM_ISRR_ADDRESS, address);
        NA_ASSERT (isrHandler !=0);      
        if (isrHandler == 0)     /* This should not happen */
        {
            customizeErrorHandler(ERROR_IRQ_TABLE, ERROR_IRQ_NESTED_IRQ_OVERFLOW);
            return 0;
        }
    }
    *NA_SCM_ICR00_ADDRESS |= (ENABLE_LEVEL_0_INTERRUPT & NAirqEnableOrWord[0]);       /* FIQ interrupts okay now*/
#endif

    /* Get Interrupt Id */
    interruptLevel = narm_read_reg(NA_SCM_ILISR_REG, NA_SCM_ILISR_ADDRESS, interruptLevel);
    interruptId = NAAhbPriorityTab[interruptLevel];
    
#if (PROCESSOR == ns9210) || (PROCESSOR == ns9215)

    if (naPdAreWeInCatnapMode) naPdFastClockCount++;
#endif
    
    /* disable this interrupt and all lower priority interrupts */
    /* then enable the master IRQ */
    if ((savedLevelIndex < MAX_AHB_INTERRUPT_LEVELS) || (savedLevelIndex < 0))
    {
        savedLevel[savedLevelIndex++] = interruptLevel;
        naMaskLowerLevelsInAhbBus(interruptLevel);
        TX_DISABLE;                     /* interrupts already disabled, just doing this to get flags*/
        interrupt_save &= ~DISABLE_IRQ; /* clear the flag bit that disables IRQ interrupts*/
        TX_RESTORE;                     /* now enable IRQ interrupts*/
    }
    else 
    { /* this should never happen*/
        customizeErrorHandler(ERROR_IRQ_TABLE, ERROR_IRQ_NESTED_IRQ_OVERFLOW);
    }        
  
    /* Execute interrupt Handler */
    (isrHandler)((void *)NAIsrTable[interruptId].isrParameter);
    
    TX_DISABLE;                         /* disable IRQ*/
    naUnmaskLowerLevelsInAhbBus(interruptLevel);
    
#if (PROCESSOR == ns9210) || (PROCESSOR == ns9215)
    *NA_SCM_ISRR_ADDRESS = interruptLevel;
    naPdSetCatnapSlowClock();
#else
    /* Clear the Interrupt */
    *NA_SCM_ISRR_ADDRESS = 0;
#endif

    --savedLevelIndex;
    if (savedLevelIndex != 0)
    {
        naMaskLowerLevelsInAhbBus(savedLevel[savedLevelIndex-1]);
    }
    NA_ASSERT(savedLevelIndex >= 0);
    return (0);
}



/*
 *  Function:   int NAInitIsr (void)
 *
 *  Description:
 *
 *      This function is to initialize the ISR table.
 *      It is called by _tx_initialize_low_level () in tx_ihl.c.
 *
 *      This function performs the following task
 *
 *          1. Verify the AHB interrupt table
 *          2. Check the BBUS interrupt table
 *          3. Initialize internal data structure
 *          4. Create priority table for each device in BBUS
 *          5. Create table which contain priorities higher than device
 *              used to mask interrupts with lower priority
 *          6. 
 *          7. Enable the BBUS Module
 *
 *  Parameter:
 *
 *      NONE
 *
 *  Return Values:
 *
 *      NONE
 */

int NAInitIsr (void)

{
    int i;
    int id;

#if PROCESSOR_HAS_BBUS
    int j;
    unsigned int    levelMask1;
    unsigned int    levelMask2;
    unsigned int    bitShift;
    unsigned int    bbusIndex;
#endif
    unsigned char   verifyInterrupts[NA_MAX_INTERRUPTS];

    if (isr_initialized)
    {
        return  (SUCCESS);
    }

    for (i = 0; i < NA_MAX_INTERRUPTS; i++)
    {
        verifyInterrupts[i] = 0;
    }

    /* Check AHB Interrupt Table */
    for (i = 0; i < AHB_MAX_INTERRUPTS; i++)
    {

        NASetInterruptVectorAddress  (i, (unsigned long) naDefaultHandler);       
        id = NAAhbPriorityTab[i];

        if ((id >= AHB_INTERRUPT_BASE) && (id < AHB_INTERRUPT_END))
        {
            verifyInterrupts[id]++;
        }
        else if ((unsigned) id != IGNORE_INTERRUPT)
        {
            /*  the NABbusPriorityTab array contains an invalid interrupt */
            customizeErrorHandler(ERROR_IRQ_TABLE, ERROR_SUBCODE_INVALID_INTERRUPT);
        }
        NAIsrTable[i].shouldInvert = FALSE;
    }

#if PROCESSOR_HAS_BBUS
    /* Check BBUS Interrupt Table */
    for (i = 0; i < BBUS_MAX_INTERRUPTS; i++)
    {
        id = NABbusPriorityTab[i];
        if (((id >= BBUS_BRIDGE_INTERRUPT_BASE) && (id < BBUS_BRIDGE_INTERRUPT_END))
                || ((id >= BBUS_DMA_INTERRUPT_BASE) && (id < BBUS_DMA_INTERRUPT_END)))
        {
            verifyInterrupts[id]++;
        }
        else if ((unsigned) id != IGNORE_INTERRUPT)
        {
            /*  the NABbusPriorityTab array contains an invalid interrupt */
            customizeErrorHandler(ERROR_IRQ_TABLE, ERROR_SUBCODE_INVALID_INTERRUPT);
        }
    }
#endif

    /* Check for duplicate entries */
    for (i = 0; i < NA_MAX_INTERRUPTS; i++)
    {
        if (verifyInterrupts[i] >= 2)
        {
            /*  the NABbusPriorityTab array contains duplicate entries    */
            customizeErrorHandler(ERROR_IRQ_TABLE, ERROR_SUBCODE_DUPLICATE_IRQ_ENTRY);
        }
    }

    /* Initialize the Interrupt Table */
    for (id = 0; id < NA_MAX_INTERRUPTS; id++)
    {
        NAIsrTable[id].id = id;
        NAIsrTable[id].inuse = NA_ISR_FREE;
        NAIsrTable[id].isrHandler = naDefaultHandler;
        NAIsrTable[id].isrParameter = (void *) id;
        NAGetIsrPriorityLevel (id, &NAIsrTable[id].priorityLevel);

        if ((id >= AHB_INTERRUPT_BASE) && (id < AHB_INTERRUPT_END))
        {
            NAIsrTable[id].idMask = 1 << (getAhbIndex(id));
        }
#if PROCESSOR_HAS_BBUS
        else if ((id >= BBUS_BRIDGE_INTERRUPT_BASE) && (id < BBUS_BRIDGE_INTERRUPT_END))
        {
            NAIsrTable[id].idMask = 1 << (getBbusBridgeIndex(id));
        }
        else if ((id >= BBUS_DMA_INTERRUPT_BASE) && (id < BBUS_DMA_INTERRUPT_END))
        {
            NAIsrTable[id].idMask = 1 << (getBbusDmaIndex(id));
        }
#endif
        else
        {
            NAIsrTable[id].idMask = 0;
        }
    }

#if PROCESSOR_HAS_BBUS

    /*
     * Configure Tables to prioritize interrupts in the BBUS
     *
     *              
     *      bbusPriorityMask (2 longwords)
     *
     *                  The BBUS Interrupts priority from Bridge and DMA are the same level; The priority
     *                  between the two types can be intermixed. So the mask for DMA can be in high or low; 
     *                  et vice versa. 
     *
     *                  By default, the Bridge interrupt happens to be in bbusPriorityMask1
     *                  and DMA interrupt in bbusPriorityMask2. But if you change the NABbusPriorityTab
     *                  to intermix then the mask in the priority mask table will be intermixed.
     *
     *                  
     *                  Table is referenced by priority level
     *            
     *                      bbusPriorityMask2                               bbusPriorityMask1
     *
     *          0   0x1111 1111 1111 1111 1111 1111 1111 1111       1111 1111 1111 1111 1111 1111 1111 1111
     *          1   0x1111 1111 1111 1111 1111 1111 1111 1111       1111 1111 1111 1111 1111 1111 1111 1110
     *          2   0x1111 1111 1111 1111 1111 1111 1111 1111       1111 1111 1111 1111 1111 1111 1111 1100
     *          3   0x1111 1111 1111 1111 1111 1111 1111 1111       1111 1111 1111 1111 1111 1111 1111 1000
     *          4   0x1111 1111 1111 1111 1111 1111 1111 1111       1111 1111 1111 1111 1111 1111 1111 0000
     *          8   0x1111 1111 1111 1111 1111 1111 1111 1111       1111 1111 1111 1111 1111 1111 0000 0000
     *          12  0x1111 1111 1111 1111 1111 1111 1111 1111       1111 1111 1111 1111 1111 0000 0000 0000
     *          16  0x1111 1111 1111 1111 1111 1111 1111 1111       1111 1111 1111 1111 0000 0000 0000 0000
     *          20  0x1111 1111 1111 1111 1111 1111 1111 1111       1111 1111 1111 0000 0000 0000 0000 0000
     *          24  0x1111 1111 1111 1111 1111 1111 1111 1111       1111 1111 0000 0000 0000 0000 0000 0000
     *          24  0x1111 1111 1111 1111 1111 1111 1111 1111       1111 0000 0000 0000 0000 0000 0000 0000
     *          32  0x1111 1111 1111 1111 1111 1111 1111 1111       0000 0000 0000 0000 0000 0000 0000 0000
     *          36  0x1111 1111 1111 1111 1111 1111 1111 0000       0000 0000 0000 0000 0000 0000 0000 0000  
     *          40  0x1111 1111 1111 1111 1111 1111 0000 0000       0000 0000 0000 0000 0000 0000 0000 0000  
     *          44  0x1111 1111 1111 1111 1111 0000 0000 0000       0000 0000 0000 0000 0000 0000 0000 0000  
     *          48  0x1111 1111 1111 1111 0000 0000 0000 0000       0000 0000 0000 0000 0000 0000 0000 0000
     *          52  0x1111 1111 1111 0000 0000 0000 0000 0000       0000 0000 0000 0000 0000 0000 0000 0000
     *          56  0x1111 1111 0000 0000 0000 0000 0000 0000       0000 0000 0000 0000 0000 0000 0000 0000
     *          60  0x1111 0000 0000 0000 0000 0000 0000 0000       0000 0000 0000 0000 0000 0000 0000 0000
     *          63  0x1000 0000 0000 0000 0000 0000 0000 0000       0000 0000 0000 0000 0000 0000 0000 0000
     *
     *      lowerLevelMask1 []    - Mask priorities lower than current PRIORITY in BBUS Bridge
     *                                Table is referenced by BBUS id
     *
     *          1                           0x1111 1111 1111 1111 1111 1111 1111 1110
     *          2                           0x1111 1111 1111 1111 1111 1111 1111 1100
     *
     *      lowerLevelMask2 []   - Mask priorities lower than current PRIORITY in BBUS DMA
     *                                Table is referenced by BBUS id
     *          1                           0x1111 1111 1111 1111 1111 1111 1111 1111
     *          2                           0x1111 1111 1111 1111 1111 1111 1111 1111
     *
     *      upperLevelInterrupt []  - Interrupts higher than the current ID interrupt
     *                                Table is referenced by BBUS id
     *          0                           1
     *          1                           2
     *          2                           3
     *          3                           4  
     */

    /* Mask for BBUS Bridge and BBUS DMA interrupts */
    levelMask1 = 0;
    levelMask2 = 0;

    /* Clear bit in mask for any interrupts ignored */
    for (i = 0; i < BBUS_MAX_INTERRUPTS; i++)
    {
        if (NABbusPriorityTab[i] == IGNORE_INTERRUPT)
        {
            continue;
        }

        /* Interrupt to ignore */
        bbusIndex = getBbusIndex (NABbusPriorityTab[i]);    
        bitShift = bbusIndex % 32;

        if ((NABbusPriorityTab[i] >= BBUS_DMA_INTERRUPT_BASE) 
            && (NABbusPriorityTab[i] < BBUS_DMA_INTERRUPT_END))
        {
            levelMask2 |= (1 << bitShift);
        }
        else
        {
            levelMask1 |= (1 << bitShift);
        }
    }
 
    /* Create the priority mask table for BBUS interrupts */
    for (i = 0; i < BBUS_MAX_INTERRUPTS; i++)
    {
        if (i && (NABbusPriorityTab[i-1] != IGNORE_INTERRUPT))
        {
            /* get index of previous priority */
            bbusIndex = getBbusIndex (NABbusPriorityTab[i-1]);    
  
            bitShift = bbusIndex % 32;
    
            /* clear bit in mask of previous priority  */
            if ((NABbusPriorityTab[i-1] >= BBUS_DMA_INTERRUPT_BASE) 
                && (NABbusPriorityTab[i-1] < BBUS_DMA_INTERRUPT_END))
            {
                levelMask2 ^= (1 << bitShift);
            }
            else
            {
                levelMask1 ^= (1 << bitShift);
            }
        }

        /* Priority mask table - process interrupts with higher priority first */
        /* Table referenced by priority */
        bbusPriorityMask1[i] = levelMask1;
        bbusPriorityMask2[i] = levelMask2;

        /* Level mask table - disables interrupt with lower priority from occuring */
        /* Table referenced by BBUS level*/
        bbusIndex = getBbusIndex (NABbusPriorityTab[i]);
        lowerLevelMask1[bbusIndex] = levelMask1;
        lowerLevelMask2[bbusIndex] = levelMask2;
    }
    
    lowerLevelMask1[BBUS_MAX_INTERRUPTS] = 0;
    lowerLevelMask2[BBUS_MAX_INTERRUPTS] = 0;

    /* Create upperLevelInterrupt Table */
    /* Use to access mask which will disable lower levels */
    for (i = 1; i < BBUS_MAX_INTERRUPTS; i++)
    {
        if (NABbusPriorityTab[i-1] == IGNORE_INTERRUPT)
        {
            continue;
        }   

        /* Get next highest interrupt which is not ignored */
        for (j = i; j < BBUS_MAX_INTERRUPTS; j++)
        {
            if (NABbusPriorityTab[j] != IGNORE_INTERRUPT)
            {
                break;
            }
        }

        bbusIndex = getBbusIndex (NABbusPriorityTab[i-1]); 

        /* get next highest interrupt for a specific BBUS interrupt */
        upperLevelInterrupt[bbusIndex] = getBbusIndex (NABbusPriorityTab[j]);
    }

    bbusIndex = getBbusIndex (NABbusPriorityTab[BBUS_MAX_INTERRUPTS - 1]); 
    upperLevelInterrupt[bbusIndex] = BBUS_MAX_INTERRUPTS;
#endif

    isr_initialized = 1;
    return  (SUCCESS);
}

/*
 *  This function intializes the Interrupt driver and enabling the BBUS and DMA 
 *  modules.
 *
 */
int NASysInit (void)
{
    static int NA_SYS_INIT = 0;

    if (NA_SYS_INIT == 1)
    {
        return (0);
    }

	NA_SYS_INIT = 1;

    /* System Control Module */

#if PROCESSOR_HAS_BBUS
    /* BBUS DMA Control Module */


    /* BBUS Bridge Module */


    /* BBUS Utility Module */
    /* Master Reset Register */
    narm_write_reg (NA_BUM_MRR_REG, NA_BUM_MRR_ADDRESS, util, 0);
    narm_write_reg (NA_BUM_MRR_REG, NA_BUM_MRR_ADDRESS, dma, 0);
#endif

    /* Interrupts */
    NAInitIsr ();
    return (0);
}

/*
 * This function returns 1 if the specified interrupt is enabled and returns 0
 * if it is not enabled, or index is out of range. 
 */
int naIsInterruptEnabled(int id)
{
    int flag = 0;

    if (isr_initialized && (id >= 0) && (id < NA_MAX_INTERRUPTS))
        flag = NAIsrTable[id].isEnabled;

    return flag;
}


    
