#include <windows.h>
#include <halether.h>
#include <bsp.h>
#include <register_map.h>
#include <Library.h>
#include "USB.h"

#define pISR		(*(volatile unsigned *)(DRAM_BASE_PA_START+0x18))

void ASM_IsrHandler(void);


volatile VIC_REG *SV210VIC0;
volatile VIC_REG *SV210VIC1;
volatile VIC_REG *SV210VIC2;

static void InitializeVIC(void)
{
	//OEMWriteDebugString("Initialize IRQ Vector Tables\r\n");
	// Disable All Interrupts

	SV210VIC0->VICINTENCLEAR = 0xFFFFFFFF;
	SV210VIC1->VICINTENCLEAR = 0xFFFFFFFF;
	SV210VIC2->VICINTENCLEAR = 0xFFFFFFFF;
	SV210VIC0->VICSOFTINTCLEAR = 0xFFFFFFFF;
	SV210VIC1->VICSOFTINTCLEAR = 0xFFFFFFFF;
	SV210VIC2->VICSOFTINTCLEAR = 0xFFFFFFFF;

	// Clear Current Active Vector Address
	SV210VIC0->VICADDRESS = 0x0;
	SV210VIC1->VICADDRESS = 0x0;
	SV210VIC2->VICADDRESS = 0x0;

	// Fill Vector Address of VIC0
	// Actually, Filled with Physical IRQ Numbers.
	// Because We do not use vectored interrupt feature
    // VIC0
    SV210VIC0->VICVECTADDR0 = PHYIRQ_EINT0;        // 0          // 0
    SV210VIC0->VICVECTADDR1 = PHYIRQ_EINT1;        // 1          // 1
    SV210VIC0->VICVECTADDR2 = PHYIRQ_EINT2;        // 2          // 2
    SV210VIC0->VICVECTADDR3 = PHYIRQ_EINT3;        // 3          // 3
    SV210VIC0->VICVECTADDR4 = PHYIRQ_EINT4;        // 4          // 4
    SV210VIC0->VICVECTADDR5 = PHYIRQ_EINT5;        // 5          // 5
    SV210VIC0->VICVECTADDR6 = PHYIRQ_EINT6;        // 6          // 6
    SV210VIC0->VICVECTADDR7 = PHYIRQ_EINT7;        // 7          // 7
    SV210VIC0->VICVECTADDR8 = PHYIRQ_EINT8;        // 8          // 8
    SV210VIC0->VICVECTADDR9 = PHYIRQ_EINT9;        // 9          // 9
    SV210VIC0->VICVECTADDR10 = PHYIRQ_EINT10;       // 10         // 10
    SV210VIC0->VICVECTADDR11 = PHYIRQ_EINT11;       // 11         // 11
    SV210VIC0->VICVECTADDR12 = PHYIRQ_EINT12;       // 12         // 12
    SV210VIC0->VICVECTADDR13 = PHYIRQ_EINT13;       // 13         // 13
    SV210VIC0->VICVECTADDR14 = PHYIRQ_EINT14;       // 14         // 14
    SV210VIC0->VICVECTADDR15 = PHYIRQ_EINT15;       // 15         // 15
    SV210VIC0->VICVECTADDR16 = PHYIRQ_EINT16_31;    // 16         // 16
    SV210VIC0->VICVECTADDR17 = PHYIRQ_RESERVED0;         // 32         // 17
    SV210VIC0->VICVECTADDR18 = PHYIRQ_MDMA;         // 33         // 18
    SV210VIC0->VICVECTADDR19 = PHYIRQ_PDMA0;        // 41         // 19
    SV210VIC0->VICVECTADDR20 = PHYIRQ_PDMA1;        // 49         // 20
    SV210VIC0->VICVECTADDR21 = PHYIRQ_TIMER0;       // 57         // 21
    SV210VIC0->VICVECTADDR22 = PHYIRQ_TIMER1;       // 58         // 22
    SV210VIC0->VICVECTADDR23 = PHYIRQ_TIMER2;       // 59         // 23
    SV210VIC0->VICVECTADDR24 = PHYIRQ_TIMER3;       // 60         // 24
    SV210VIC0->VICVECTADDR25 = PHYIRQ_TIMER4;       // 61         // 25
    SV210VIC0->VICVECTADDR26 = PHYIRQ_SYSTIMER;     // 62         // 26
    SV210VIC0->VICVECTADDR27 = PHYIRQ_WDT;          // 63         // 27
    SV210VIC0->VICVECTADDR28 = PHYIRQ_RTC_ALARM;    // 64         // 28
    SV210VIC0->VICVECTADDR29 = PHYIRQ_RTC_TIC;      // 65         // 29
    SV210VIC0->VICVECTADDR30 = PHYIRQ_GPIO;         // 66         // 30
    SV210VIC0->VICVECTADDR31 = PHYIRQ_RESERVED0;    // 67         // 31

    // VIC1
    SV210VIC1->VICVECTADDR0 = PHYIRQ_CORTEX0;      // 68         // 32
    SV210VIC1->VICVECTADDR1 = PHYIRQ_CORTEX1;      // 69         // 33
    SV210VIC1->VICVECTADDR2 = PHYIRQ_CORTEX2;      // 70         // 34
    SV210VIC1->VICVECTADDR3 = PHYIRQ_CORTEX3;      // 71         // 35
    SV210VIC1->VICVECTADDR4 = PHYIRQ_CORTEX4;      // 72         // 36
    SV210VIC1->VICVECTADDR5 = PHYIRQ_IEMAPC;       // 73         // 37
    SV210VIC1->VICVECTADDR6 = PHYIRQ_IEMIEC;       // 74         // 38
    SV210VIC1->VICVECTADDR7 = PHYIRQ_RESERVED1;     // 75         // 39
    SV210VIC1->VICVECTADDR8 = PHYIRQ_NFC;          // 76         // 40
    SV210VIC1->VICVECTADDR9 = PHYIRQ_CFC;          // 77         // 41
    SV210VIC1->VICVECTADDR10 = PHYIRQ_UART0;        // 78         // 42
    SV210VIC1->VICVECTADDR11 = PHYIRQ_UART1;        // 79         // 43
    SV210VIC1->VICVECTADDR12 = PHYIRQ_UART2;        // 80         // 44
    SV210VIC1->VICVECTADDR13 = PHYIRQ_UART3;        // 81         // 45
    SV210VIC1->VICVECTADDR14 = PHYIRQ_I2C;          // 82         // 46
    SV210VIC1->VICVECTADDR15 = PHYIRQ_SPI0;         // 83         // 47
    SV210VIC1->VICVECTADDR16 = PHYIRQ_SPI1;         // 84         // 48
    SV210VIC1->VICVECTADDR17 = PHYIRQ_SPI2;         // 85         // 49
    SV210VIC1->VICVECTADDR18 = PHYIRQ_AUDIO_SS;         // 86         // 50
    SV210VIC1->VICVECTADDR19 = PHYIRQ_I2C_PMIC_LINK;         // 87         // 51
    SV210VIC1->VICVECTADDR20 = PHYIRQ_I2C_HDMI_PHY;         // 88         // 52
    SV210VIC1->VICVECTADDR21 = PHYIRQ_HSIRX;        // 89         // 53
    SV210VIC1->VICVECTADDR22 = PHYIRQ_HSITX;        // 90         // 54
    SV210VIC1->VICVECTADDR23 = PHYIRQ_UHOST;        // 91         // 55
    SV210VIC1->VICVECTADDR24 = PHYIRQ_OTG;          // 92         // 56
    SV210VIC1->VICVECTADDR25 = PHYIRQ_MSM;          // 93         // 57
    SV210VIC1->VICVECTADDR26 = PHYIRQ_SDMMC0;       // 94         // 58
    SV210VIC1->VICVECTADDR27 = PHYIRQ_SDMMC1;       // 95         // 59
    SV210VIC1->VICVECTADDR28 = PHYIRQ_SDMMC2;       // 96         // 60
    SV210VIC1->VICVECTADDR29 = PHYIRQ_MIPI_CSI;     // 97         // 61
    SV210VIC1->VICVECTADDR30 = PHYIRQ_MIPI_DSI;     // 98         // 62
    SV210VIC1->VICVECTADDR31 = PHYIRQ_RESERVED1;    // 99         // 63

    // VIC2
    SV210VIC2->VICVECTADDR0 = PHYIRQ_LCD0;         // 100        // 64
    SV210VIC2->VICVECTADDR1 = PHYIRQ_LCD1;         // 101        // 65
    SV210VIC2->VICVECTADDR2 = PHYIRQ_LCD2;         // 102        // 66
    SV210VIC2->VICVECTADDR3 = PHYIRQ_LCD3;         // 103        // 67
    SV210VIC2->VICVECTADDR4 = PHYIRQ_ROTATOR;      // 104        // 68
    SV210VIC2->VICVECTADDR5 = PHYIRQ_FIMC0;        // 105        // 69
    SV210VIC2->VICVECTADDR6 = PHYIRQ_FIMC1;        // 106        // 70
    SV210VIC2->VICVECTADDR7 = PHYIRQ_FIMC2;        // 107        // 71
    SV210VIC2->VICVECTADDR8 = PHYIRQ_JPEG;         // 108        // 72
    SV210VIC2->VICVECTADDR9 = PHYIRQ_2D;           // 109        // 73
    SV210VIC2->VICVECTADDR10 = PHYIRQ_3D;           // 110        // 74
    SV210VIC2->VICVECTADDR11 = PHYIRQ_MIXER;        // 111        // 75
    SV210VIC2->VICVECTADDR12 = PHYIRQ_HDMI;         // 112        // 76
    SV210VIC2->VICVECTADDR13 = PHYIRQ_HDMI_I2C;     // 113        // 77
    SV210VIC2->VICVECTADDR14 = PHYIRQ_MFC;          // 114        // 78
    SV210VIC2->VICVECTADDR15 = PHYIRQ_TVENC;        // 115        // 79
    SV210VIC2->VICVECTADDR16 = PHYIRQ_I2S0;         // 116        // 80
    SV210VIC2->VICVECTADDR17 = PHYIRQ_I2S1;         // 117        // 81
    SV210VIC2->VICVECTADDR18 = PHYIRQ_RESERVED2;         // 118        // 82
    SV210VIC2->VICVECTADDR19 = PHYIRQ_AC97;         // 119        // 83
    SV210VIC2->VICVECTADDR20 = PHYIRQ_PCM0;         // 120        // 84
    SV210VIC2->VICVECTADDR21 = PHYIRQ_PCM1;         // 121        // 85
    SV210VIC2->VICVECTADDR22 = PHYIRQ_SPDIF;        // 122        // 86
    SV210VIC2->VICVECTADDR23 = PHYIRQ_ADC;          // 123        // 87
    SV210VIC2->VICVECTADDR24 = PHYIRQ_PENDN;        // 124        // 88
    SV210VIC2->VICVECTADDR25 = PHYIRQ_KEYPAD;       // 125        // 89
    SV210VIC2->VICVECTADDR26 = PHYIRQ_SPG;          // 126        // 90
    SV210VIC2->VICVECTADDR27 = PHYIRQ_IntHash_SSS;          // 127        // 91
    SV210VIC2->VICVECTADDR28 = PHYIRQ_IntFeedCtrl_SSS;       // 128        // 92
    SV210VIC2->VICVECTADDR29 = PHYIRQ_RESERVED3;       // 129        // 93
    SV210VIC2->VICVECTADDR30 = PHYIRQ_SDM_FIQ;      // 130        // 94
    SV210VIC2->VICVECTADDR31 = PHYIRQ_SDM_IRQ;      // 131        // 95

	// Enable IRQ Interrupt on CP15
	System_EnableIRQ();
}

void INTC_Enable(UINT32 intNum)
{
	volatile UINT32 temp;

	if(intNum<32)
	{
		//temp = Inp32(rVIC0INTENABLE);
		temp = SV210VIC0->VICINTENABLE;
		temp |= (1<<intNum);
		//Outp32(rVIC0INTENABLE, temp);
		SV210VIC0->VICINTENABLE = temp;
	}
	else if(intNum<64)
	{
		//temp = Inp32(rVIC1INTENABLE);
		temp = SV210VIC1->VICINTENABLE;
		temp |= (1<<(intNum-32));
		//Outp32(rVIC1INTENABLE, temp);
		SV210VIC1->VICINTENABLE = temp;
	}
	else
	{
		//temp = Inp32(rVIC1INTENABLE);
		temp = SV210VIC2->VICINTENABLE;
		temp |= (1<<(intNum-32));
		//Outp32(rVIC1INTENABLE, temp);
		SV210VIC2->VICINTENABLE = temp;
	}

	return;
}

void INTC_Disable(UINT32 intNum)
{
	volatile UINT32 temp;

	if(intNum<32)
	{
		//temp = Inp32(rVIC0INTENCLEAR);
		temp = SV210VIC0->VICINTENCLEAR;
		temp |= (1<<intNum);
		//Outp32(rVIC0INTENCLEAR, temp);
		SV210VIC0->VICINTENCLEAR = temp;
	}
	else if(intNum<64)
	{
		//temp = Inp32(rVIC1INTENCLEAR);
		temp = SV210VIC1->VICINTENCLEAR;
		temp |= (1<<(intNum-32));
		//Outp32(rVIC1INTENCLEAR, temp);
		SV210VIC1->VICINTENCLEAR = temp;
	}
    else
	{
		//temp = Inp32(rVIC1INTENCLEAR);
		temp = SV210VIC2->VICINTENCLEAR;
		temp |= (1<<(intNum-32));
		//Outp32(rVIC1INTENCLEAR, temp);
		SV210VIC2->VICINTENCLEAR = temp;
	}
	return;
}

#pragma optimize ("",off)
VOID INTC_ClearVectAddr(VOID)
{
	SV210VIC0->VICADDRESS = 0x0;
	SV210VIC1->VICADDRESS = 0x0;
   	SV210VIC2->VICADDRESS = 0x0;
}

VOID InitializeInterrupt(VOID)
{
    EdbgOutputDebugString("+++InitializeInterrupt()\r\n");
    
	SV210VIC0 = (PVIC_REG)BASE_REG_PA_VIC0;
	SV210VIC1 = (PVIC_REG)BASE_REG_PA_VIC1;
	SV210VIC2 = (PVIC_REG)BASE_REG_PA_VIC2;

	InitializeVIC();
	
	INTC_ClearVectAddr();
	
	EdbgOutputDebugString("---InitializeInterrupt()\r\n");
}
#pragma optimize ("",on)

void C_IsrHandler(unsigned int val)
{

	INTC_Disable(PHYIRQ_OTG);

    //EdbgOutputDebugString("IsrUsbd is called\r\n");

	OTGDEV_HandleEvent();

	INTC_Enable(PHYIRQ_OTG);

	INTC_ClearVectAddr();

}
