/**
 * This function will install a interrupt service routine to a interrupt.
 * @param vector the interrupt number
 * @param new_handler the interrupt service routine to be installed
 * @param old_handler the old interrupt service routine
 */
void rt_hw_interrupt_install(int vector, rt_isr_handler_t new_handler, rt_isr_handler_t *old_handler)
{
	if(vector >= 0 && vector < MAX_HANDLERS)
	{
		if (*old_handler != RT_NULL) *old_handler = (rt_isr_handler_t)AT91C_AIC_SVR(vector);
		if (new_handler != RT_NULL) AT91C_AIC_SVR(vector) = (rt_uint32_t)new_handler;
	}
}
/**
 * This function will initialize hardware interrupt
 */
void rt_hw_interrupt_init()
{
	rt_base_t index;

	for (index = 0; index < MAX_HANDLERS; index ++)
	{
		AT91C_AIC_SVR(index) = (rt_uint32_t)rt_hw_interrupt_handler;
	}

	/* init interrupt nest, and context in thread sp */
	rt_interrupt_nest = 0;
	rt_interrupt_from_thread = 0;
	rt_interrupt_to_thread = 0;
	rt_thread_switch_interrupt_flag = 0;
}
/*-----------------------------------------------------------------------------
 * Function Name     : lowlevel_init
 * Object            : This function performs very low level HW initialization
 *                     this function can use a Stack, depending the compilation
 *                     optimization mode
 *---------------------------------------------------------------------------*/
void lowlevel_init(void)
{
    unsigned char i = 0;

    /* void default_fiq_handler(void)
     * Init PMC Step 1. Enable Main Oscillator
     * Main Oscillator startup time is board specific:
     * Main Oscillator Startup Time worst case (3MHz) corresponds to 15ms
     * (0x40 for AT91C_CKGR_OSCOUNT field)
     */
    AT91C_PMC_MOR = (((AT91C_CKGR_OSCOUNT & (0x40 << 8)) | AT91C_CKGR_MOSCEN));
    /* Wait Main Oscillator stabilization */
    while (!(AT91C_PMC_SR & AT91C_PMC_MOSCS));

    /* Init PMC Step 2.
     * Set PLLA to 198,608MHz
     * PLL Startup time depends on PLL RC filter: worst case is choosen.
     *
     * Crystal frequency = 18.432MHz; PLLA = (18.432 * 96) / 9 = 198,608MHz.
     */

    AT91C_PMC_PLLAR = (1 << 29)       |
                      (0x60 << 16)    | /* MULA = 96 */
                      (0x2 << 14)     |
                      (0x3f << 8)     |
                      (0x09); /* DIVA = 9 */

    /* Wait for PLLA stabilization */
    while (!(AT91C_PMC_SR & AT91C_PMC_LOCKA));
    /* Wait until the master clock is established for the case we already */
    /* turn on the PLLA */
    while (!(AT91C_PMC_SR & AT91C_PMC_MCKRDY));

    /* Init PMC Step 3.
     * Processor Clock = 198,608MHz (PLLA); Master clock =
     * (198,608MHz (PLLA))/2 = 98,304MHz.
     * The PMC_MCKR register must not be programmed in a single write operation
     * (see. Product Errata Sheet)
     */
    AT91C_PMC_MCKR = AT91C_PMC_PRES_CLK | AT91C_PMC_MDIV_2;
    /* Wait until the master clock is established */
    while (!(AT91C_PMC_SR & AT91C_PMC_MCKRDY));

    AT91C_PMC_MCKR |= AT91C_PMC_CSS_PLLA_CLK;
    /* Wait until the master clock is established */
    while (!(AT91C_PMC_SR & AT91C_PMC_MCKRDY));

    /* Reset AIC: assign default handler for each interrupt source
     */

    /* Disable the interrupt on the interrupt controller */
    AT91C_AIC_IDCR = (1 << AT91C_ID_SYS);

    /* Assign default handler for each IRQ source */
    AT91C_AIC_SVR(AT91C_ID_FIQ) = (int) default_fiq_handler;
    for (i = 1; i < 31; i++)
    {
        AT91C_AIC_SVR(i) = (int) default_irq_handler;
    }
    AT91C_AIC_SPU = (unsigned int) default_spurious_handler;

    /* Perform 8 IT acknoledge (write any value in EOICR) */

/* The End of Interrupt Command Register (AIC_EOICR) must be written in order
to indicate to the AIC that the current interrupt is finished. This causes the
current level to be popped from the stack, restoring the previous current level
if one exists on the stack. If another interrupt is pending, with lower or
equal priority than the old current level but with higher priority than the new
current level, the nIRQ line is re-asserted, but the interrupt sequence does
not immediately start because the “I” bit is set in the core.
SPSR_irq is restored. Finally, the saved value of the link register is restored
directly into the PC. This has the effect of returning from the interrupt to
whatever was being executed before, and of loading the CPSR with the stored
SPSR, masking or unmasking the interrupts depending on the state saved in
SPSR_irq. */
    for (i = 0; i < 8 ; i++)
    {
        AT91C_AIC_EOICR = 0;
    }

    /* Enable the interrupt on the interrupt controller */
    AT91C_AIC_IECR = (1 << AT91C_ID_SYS);

    /* Disable Watchdog */
    AT91C_WDTC_WDMR = AT91C_WDTC_WDDIS;

    /* Remap */
    AT91C_MATRIX_MRCR = AT91C_MATRIX_RCA926I | AT91C_MATRIX_RCA926D;
}