#include <windows.h>
#include <bsp_args.h>
#include <oal_log.h>

#include "menu.h"
#include <Bsp.h>
#include <loader.h>
#include <clkinfo.h>

extern SYSTEM_CLOCK g_SysClockTable[SYS_CLK_DEF_MAX];

extern PBOOT_CFG       g_pBootCfg;

void ClockChange(void *pCMUCLKreg, void *pDMC0reg, void *pDMC1reg, void *pCLKInfo);


static void MenuTitleCLKChange(void *arg)
{

	switch((int)arg) 
	{
		case 0:
			EdbgOutputDebugString("ARMCLK:%dMHz, HCLK_MSYS:%dMHz, HCLK_DSYS:%dMHz, HCLK_PSYS:%dMHz",g_SysClockTable[SYS_CLK_DEF0].ARM_CLK/1000000,
                                                                                                    g_SysClockTable[SYS_CLK_DEF0].HCLKMSYS_CLK/1000000,
                                                                                                    g_SysClockTable[SYS_CLK_DEF0].HCLKDSYS_CLK/1000000, 
                                                                                                    g_SysClockTable[SYS_CLK_DEF0].HCLKPSYS_CLK/1000000);
			break;
		case 1:
			EdbgOutputDebugString("ARMCLK: %dMHz, HCLK_MSYS:%dMHz, HCLK_DSYS:%dMHz, HCLK_PSYS:%dMHz", g_SysClockTable[SYS_CLK_DEF1].ARM_CLK/1000000,
                                                                                                     g_SysClockTable[SYS_CLK_DEF1].HCLKMSYS_CLK/1000000, 
                                                                                                     g_SysClockTable[SYS_CLK_DEF1].HCLKDSYS_CLK/1000000, 
                                                                                                     g_SysClockTable[SYS_CLK_DEF1].HCLKPSYS_CLK/1000000);
			break;
		case 2:
			EdbgOutputDebugString("ARMCLK: %dMHz, HCLK_MSYS:%dMHz, HCLK_DSYS:%dMHz, HCLK_PSYS:%dMHz", g_SysClockTable[SYS_CLK_DEF2].ARM_CLK/1000000, 
                                                                                                     g_SysClockTable[SYS_CLK_DEF2].HCLKMSYS_CLK/1000000, 
                                                                                                     g_SysClockTable[SYS_CLK_DEF2].HCLKDSYS_CLK/1000000, 
                                                                                                     g_SysClockTable[SYS_CLK_DEF2].HCLKPSYS_CLK/1000000);
    		break;
        case 3:
 			EdbgOutputDebugString("ARMCLK: %dMHz, HCLK_MSYS:%dMHz, HCLK_DSYS:%dMHz, HCLK_PSYS:%dMHz", g_SysClockTable[SYS_CLK_DEF3].ARM_CLK/1000000, 
                                                                                                     g_SysClockTable[SYS_CLK_DEF3].HCLKMSYS_CLK/1000000, 
                                                                                                     g_SysClockTable[SYS_CLK_DEF3].HCLKDSYS_CLK/1000000, 
                                                                                                     g_SysClockTable[SYS_CLK_DEF3].HCLKPSYS_CLK/1000000);
    		break;

        case 'P':    
            EdbgOutputDebugString("Current System Clocks\r\n");
            if((g_pBootCfg->Clock_Info.SYS_CLK_DEF>(SYS_CLK_DEF_MAX -1))||(g_pBootCfg->Clock_Info.SYS_CLK_DEF<0)||(g_pBootCfg->Clock_Info.ARM_CLK == 0))
            EdbgOutputDebugString("EbootCFG Clock is not Defined.\r\n");
            else
 			EdbgOutputDebugString("   ARMCLK: %dMHz, HCLK_MSYS:%dMHz, HCLK_DSYS:%dMHz, HCLK_PSYS:%dMHz", g_pBootCfg->Clock_Info.ARM_CLK/1000000, 
                                                                                                     g_pBootCfg->Clock_Info.HCLKMSYS_CLK/1000000, 
                                                                                                     g_pBootCfg->Clock_Info.HCLKDSYS_CLK/1000000, 
                                                                                                     g_pBootCfg->Clock_Info.HCLKPSYS_CLK/1000000);

            break;
            
	}
}

static int MenuHandlerCLKChange(void *arg)
{

    static volatile CMU_CLK_REG *pCMUCLKReg;
    static volatile DRAMCON_REG *pDMC0Reg;
    static volatile DRAMCON_REG *pDMC1Reg;

    pCMUCLKReg = (volatile CMU_CLK_REG*)OALPAtoVA(BASE_REG_PA_CMU_CLK, FALSE);
    pDMC0Reg = (volatile DRAMCON_REG*)OALPAtoVA(BASE_REG_PA_DMC0, FALSE);
    pDMC1Reg = (volatile DRAMCON_REG*)OALPAtoVA(BASE_REG_PA_DMC1, FALSE);
    
	switch((int)arg) 
	{
		case 0:
                memcpy(&g_pBootCfg->Clock_Info, &g_SysClockTable[SYS_CLK_DEF0], sizeof(g_pBootCfg->Clock_Info));
                ClockChange((void *)pCMUCLKReg, (void *)pDMC0Reg, (void *)pDMC1Reg, &g_pBootCfg->Clock_Info);
			break;
		case 1:
                memcpy(&g_pBootCfg->Clock_Info, &g_SysClockTable[SYS_CLK_DEF1], sizeof(g_pBootCfg->Clock_Info));
                ClockChange((void *)pCMUCLKReg, (void *)pDMC0Reg, (void *)pDMC1Reg, &g_pBootCfg->Clock_Info);
			break;
		case 2:
			    memcpy(&g_pBootCfg->Clock_Info, &g_SysClockTable[SYS_CLK_DEF2], sizeof(g_pBootCfg->Clock_Info));
                ClockChange((void *)pCMUCLKReg, (void *)pDMC0Reg, (void *)pDMC1Reg, &g_pBootCfg->Clock_Info);
    		break;
        case 3:
 			    memcpy(&g_pBootCfg->Clock_Info, &g_SysClockTable[SYS_CLK_DEF3], sizeof(g_pBootCfg->Clock_Info));
                ClockChange((void *)pCMUCLKReg, (void *)pDMC0Reg, (void *)pDMC1Reg, &g_pBootCfg->Clock_Info);
    		break;
            
        case 'P':
 			    EdbgOutputDebugString("P key is information for current clocks");
    		break;              
	}    
	return 0;
}

// Function to be called when exiting this menu
void MenuExitCLKChange(void *arg)
{
    TOC_Write();
    memcpy(&g_pBSPArgs->SystemClocks, &g_pBootCfg->Clock_Info, sizeof(g_pBSPArgs->SystemClocks));
}

MENU_ITEM m_menuClockChange[] =
{
    { 'P', "Menu Name", MenuTitleCLKChange, NULL, NULL, NULL, NULL,(void *) 'P'},
	{ '0', "Menu Name", MenuTitleCLKChange, MenuHandlerCLKChange, NULL, NULL, NULL, (void *) 0},
	{ '1', "Menu Name", MenuTitleCLKChange, MenuHandlerCLKChange, NULL, NULL, NULL, (void *) 1},
	{ '2', "Menu Name", MenuTitleCLKChange, MenuHandlerCLKChange, NULL, NULL, NULL, (void *) 2},
	{ '3', "Menu Name", MenuTitleCLKChange, MenuHandlerCLKChange, NULL, NULL, NULL, (void *) 3},	
	{ '\0', "", NULL, NULL, NULL, (void *) NULL}
};


