/*
 *  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
 *
 *  ====================================================================
 *  This is a simple IRQ handler for bootloader.  This version is used
 *  to reduce the amount of code space to a minimum and because the
 *  general purpose IRQ handler was scheduled to be rewritten at the
 *  time the bootloader was ported to NS9750.
 *
 */

#ifdef BSP_ARM9

#include <stdlib.h>
#include "Npttypes.h"
#include "reg_def.h"
#include "mcsys_reg.h"
#include "tx_api.h" /* for TX_ENABLE and TX_DISABLE*/
#include "blIRQ.h"
#include "NA_ISR.h"

typedef struct
{
    int id;
    IRQHandlerType handler;
} IRQType;

void ARM9_IRQ_Handler(void);

/*
 * This table is index by interrupt priority, not device id.
 * It lists all of the interrupts in the system.
 */
static IRQType IRQ[NA_SCM_IVAR_MAX] = {{0}};

static void IRQWriteICR(unsigned priority, unsigned id, int enabled)
{
    switch (priority % 5)
    {
        case 0:
            narm_write_reg(NA_SCM_ICR0_REG, ICR_getAddress(priority), enable, SCM_ICR_DISABLE);
            narm_write_reg(NA_SCM_ICR0_REG, ICR_getAddress(priority), invert, 0);
            narm_write_reg(NA_SCM_ICR0_REG, ICR_getAddress(priority), type, SCM_ICR_IRQ);
            narm_write_reg(NA_SCM_ICR0_REG, ICR_getAddress(priority), id, id);
            narm_write_reg(NA_SCM_ICR0_REG, ICR_getAddress(priority), enable, enabled);
            break;
        case 1:
            narm_write_reg(NA_SCM_ICR1_REG, ICR_getAddress(priority), enable, SCM_ICR_DISABLE);
            narm_write_reg(NA_SCM_ICR1_REG, ICR_getAddress(priority), invert, 0);
            narm_write_reg(NA_SCM_ICR1_REG, ICR_getAddress(priority), type, SCM_ICR_IRQ);
            narm_write_reg(NA_SCM_ICR1_REG, ICR_getAddress(priority), id, id);
            narm_write_reg(NA_SCM_ICR1_REG, ICR_getAddress(priority), enable, enabled);
            break;
        case 2:
            narm_write_reg(NA_SCM_ICR2_REG, ICR_getAddress(priority), enable, SCM_ICR_DISABLE);
            narm_write_reg(NA_SCM_ICR2_REG, ICR_getAddress(priority), invert, 0);
            narm_write_reg(NA_SCM_ICR2_REG, ICR_getAddress(priority), type, SCM_ICR_IRQ);
            narm_write_reg(NA_SCM_ICR2_REG, ICR_getAddress(priority), id, id);
            narm_write_reg(NA_SCM_ICR2_REG, ICR_getAddress(priority), enable, enabled);
            break;
        case 3:
            narm_write_reg(NA_SCM_ICR3_REG, ICR_getAddress(priority), enable, SCM_ICR_DISABLE);
            narm_write_reg(NA_SCM_ICR3_REG, ICR_getAddress(priority), invert, 0);
            narm_write_reg(NA_SCM_ICR3_REG, ICR_getAddress(priority), type, SCM_ICR_IRQ);
            narm_write_reg(NA_SCM_ICR3_REG, ICR_getAddress(priority), id, id);
            narm_write_reg(NA_SCM_ICR3_REG, ICR_getAddress(priority), enable, enabled);
            break;
		case 4:
            narm_write_reg(NA_SCM_ICR0_REG, ICR_getAddress(priority), enable, SCM_ICR_DISABLE);
            narm_write_reg(NA_SCM_ICR0_REG, ICR_getAddress(priority), invert, 0);
            narm_write_reg(NA_SCM_ICR0_REG, ICR_getAddress(priority), type, SCM_ICR_IRQ);
            narm_write_reg(NA_SCM_ICR0_REG, ICR_getAddress(priority), id, id);
            narm_write_reg(NA_SCM_ICR0_REG, ICR_getAddress(priority), enable, enabled);
            break;
    }
}



void BlIRQ_Handler(void)
{
    /* register int interrupt_save=0; */ /* enable value*/
/*
 * Read interrupt vector from Interrupt Controller.
 */
    IRQHandlerType handler = (IRQHandlerType) *NA_SCM_ISRR_ADDRESS;
    unsigned interruptLevel = narm_read_reg(NA_SCM_ILISR_REG, NA_SCM_ILISR_ADDRESS, interruptLevel);
    
/*
 * Enable IRQ level interrupts and call the handler.  Interrupt controller
 * will allow higher priority interrupts to occur.  TX_RESTORE will enable
 * interrupts since interrupt_save is set to 0, and store the interrupt
 * disabled value into interrupt_save.
 */
//    TX_RESTORE;
    handler();
    
/*
 * When the handler returns, disable IRQ interrupts and clear the interrupt
 * by writing to the vector register.  IRQ interrupts will be reenabled when
 * we return and switch to SVC mode.  The interrupt_save flag was set with
 * the disabled value the first time TX_RESTORE was called, so this time it
 * will disable the interrupts.
 */
//    TX_DISABLE;
#if (PROCESSOR == ns9215) || (PROCESSOR == NS9210)
    *NA_SCM_ISRR_ADDRESS = interruptLevel;
#else
    *NA_SCM_ISRR_ADDRESS = (unsigned long)NULL;
#endif
}

static void IRQInitialize(void)
{
    int priority;
    
/*
 * Make sure all interrupts are disabled.
 */
    for (priority = 0; priority < NA_SCM_IVAR_MAX; priority++)
    {
        IRQWriteICR(priority, 0, SCM_ICR_DISABLE);
    }

/*
 * Make sure our handler is installed.
 */
	NASetIRQ(IRQ_ENABLED);
    *(WORD32 *)(0x38) = (WORD32) ARM9_IRQ_Handler;
}

    
int IRQInstall(unsigned id, unsigned priority, IRQHandlerType handler)
{
    NA_ASSERT(priority < NA_SCM_IVAR_MAX);
    NA_ASSERT(id < NA_SCM_IVAR_MAX);
    
/*
 * Record the IRQ handler and device ID.
 */
    IRQ[priority].handler = handler;
    IRQ[priority].id = id;
    *IVAR_getAddress(priority) = (WORD32) IRQ[priority].handler;
    
    return IRQ_SUCCESS;
}


int IRQEnable(unsigned priority)
{
    static int initialized = FALSE;
    
    NA_ASSERT(priority < NA_SCM_IVAR_MAX);
    
    if (!initialized)
    {
        IRQInitialize();
        initialized = TRUE;
    }
    
    IRQWriteICR(priority, IRQ[priority].id, SCM_ICR_ENABLE);
    
    return IRQ_SUCCESS;
}


int IRQDisable(unsigned priority)
{
    NA_ASSERT(priority < NA_SCM_IVAR_MAX);
    
    IRQWriteICR(priority, IRQ[priority].id, SCM_ICR_DISABLE);
    
    return IRQ_SUCCESS;
}


#endif
