//
// 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.
//

#include <windows.h>
#include <halether.h>
#include <bsp.h>
#include <register_map.h>
#include "loader.h"
// 070514 by mkkim@nsusemi.com 
#include "usbintr.h"
#include "usbapi.h"
#include "usb.h"
#include <delay.h>

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

static volatile VIC_REG *g_pVIC0Reg;
static volatile VIC_REG *g_pVIC1Reg;
static volatile VIC_REG *g_pVIC2Reg;

extern BOOL g_USBRequest; // Add to Emergency Download Mode (silisand)
extern volatile UINT32 g_dwDownIndex;
extern volatile UINT8  *g_pDownPt;

extern void ASM_IsrHandler(void);
extern void OTGDEV_DeInitOtg(void);
volatile VIC_REG *sV210VIC0;
volatile VIC_REG *sV210VIC1;
volatile VIC_REG *sV210VIC2;

//////////
// Function Name : USB_Clock_Init
// Function Desctiption : This function initialize USB Clock
// Input : NONE
// Output : NONE
// Version :

//////////
// Function Name : INTC_Enable
// Function Description : This function sets the corresponding bit of interrupt enable register
// Input : intNum, interrupt number to be enabled
// Output : NONE
// Version :
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;
}

//////////
// Function Name : INTC_ClearVectAddr
// Function Description : This function clears the vector address register
// Input : NONE
// Output : NONE
// Version :
void INTC_ClearVectAddr(void)
{
	sV210VIC0->VICADDRESS = 0x0;
	sV210VIC1->VICADDRESS = 0x0;
   	sV210VIC2->VICADDRESS = 0x0;

	return;
}

void USB_Clock_Init(void)
{
    volatile CMU_CLK_REG *pSYSCON_CLKReg;
	pSYSCON_CLKReg = (CMU_CLK_REG *)OALPAtoVA(BASE_REG_PA_CMU_CLK, FALSE);
	pSYSCON_CLKReg->CLK_GATE.CLK_GATE_IP1 |= (CLK_ON<<BP_CLK_IP_USBOTG); 	//OTG HClk enable
}

void USB_Clock_DeInit(void)
{
    volatile CMU_CLK_REG *g_pSYSCON_CLKReg=(CMU_CLK_REG *)OALPAtoVA(BASE_REG_PA_CMU_CLK, FALSE);
	g_pSYSCON_CLKReg->CLK_GATE.CLK_GATE_IP1 &= ~(CLK_ON<<BP_CLK_IP_USBOTG); 	//OTG HClk disable
}


void USBInit(void)
{
    //USBSelect(USB_PATH_NONE);
    OALWaitUsec(200);
    OALWaitUsec(200);
    USB_Clock_Init();

	USBConnect(FALSE);
//	USBSelect(USB_PATH_PDA);
    EdbgOutputDebugString("EOTG: USB Init \r\n");
}

void USBDeInit()
{

    // OTG Power off
   	USBConnect(FALSE);
    //USBSelect(USB_PATH_NONE);
    OALWaitUsec(200);
    OALWaitUsec(200);
    USB_Clock_DeInit();
	OTGDEV_DeInitOtg();

    //USBSelect(USB_PATH_PDA);

    // OTG interrupt disable
	INTC_Disable(PHYIRQ_OTG);
    EdbgOutputDebugString("EOTG: USB DeInit \r\n");
}

BOOL InitOTG(BOOL bHIGH)
{
	sV210VIC0 = (VIC_REG *)OALPAtoVA(BASE_REG_PA_VIC0, FALSE);
	sV210VIC1 = (VIC_REG *)OALPAtoVA(BASE_REG_PA_VIC1, FALSE);
	sV210VIC2 = (VIC_REG *)OALPAtoVA(BASE_REG_PA_VIC2, FALSE);  

	if(bHIGH)
		OTGDEV_InitOtg(USB_HIGH);
	else
		OTGDEV_InitOtg(USB_FULL);


	g_USBRequest = FALSE; // Add to Emergency Download Mode (silisand)

	INTC_Enable(PHYIRQ_OTG);

	return TRUE;
}

BOOL InitializeUSB()
{
	OTGDEV_InitOtg(USB_HIGH);
	return TRUE;
}

static void InitializeVIC(void)
{
	RETAILMSG(1,(TEXT("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 InitializeInterrupt(void)
{
	sV210VIC0 = (VIC_REG *)OALPAtoVA(BASE_REG_PA_VIC0, FALSE);
	sV210VIC1 = (VIC_REG *)OALPAtoVA(BASE_REG_PA_VIC1, FALSE);
	sV210VIC2 = (VIC_REG *)OALPAtoVA(BASE_REG_PA_VIC2, FALSE);

	InitializeVIC();

	// make value to assemble code "b IsrHandler"
	//EdbgOutputDebugString("INFO: (unsigned)pISR : 0x%x\r\n", (unsigned)pISR);
//pISR =(unsigned)(0xEA000000)+(((unsigned)ASM_IsrHandler - (0x80000000 + 0x18 + 0x8) )>>2);

    pISR = 0xE59FF3D8;          // LDR PC, [PC, #3E0 - 8]
    *((volatile unsigned long *)(0x3F8)) = (unsigned)ASM_IsrHandler;

	EdbgOutputDebugString("EOTG: USB DeInit 0x%x\r\n",(pISR));
	INTC_ClearVectAddr();

	//INTC_Enable(PHYIRQ_OTG);
}

void C_IsrHandler(unsigned int val)
{

	INTC_Disable(PHYIRQ_OTG);

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

	OTGDEV_HandleEvent();

	INTC_Enable(PHYIRQ_OTG);

	INTC_ClearVectAddr();

}


