/**************************************************************************//**
 * @file     TouchPanel.c
 * @brief    Demonstration wake up system by touching panel 
 *
 * SPDX-License-Identifier: Apache-2.0
 * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include <stdio.h>
#include "N9H20.h"
char u8Tmp[0x1000];
extern void Sample_PowerDown(void);
//extern void pfnRecordCallback(void);

#define POWER_DOWN
//static volatile BOOL g_i8PcmReady = FALSE;
static void pfnWaitForTriggerCallback(void)
{
	//g_i8PcmReady = 1;
	//TBD...
}
static void pfnRecordCallback(void)
{
	//g_i8PcmReady = 1;
	//TBD...
}
#pragma diag_suppress 1287
void Sample_PowerDown(void)
{	
	register int reg2, reg1, reg0;
	/* Enter self refresh */	
	outp32(REG_SDCMD, inp32(REG_SDCMD) | 0x10);
#if defined (__GNUC__)
	__asm volatile
	(
		"  mov 	%0, #100       \n"
		"  mov  %1, #0         \n"
		"  mov  %2, #1         \n"
		" loopa:	           \n"
		"  add  %1, %1, %2     \n"
		"  cmp 	%1, %0         \n"
		"  bne  loopa          \n"
		: : "r"(reg2), "r"(reg1), "r"(reg0) :"memory"
	);
#else
	__asm
	{/* Dealy */
		mov 	reg2, #100
		mov		reg1, #0
		mov		reg0, #1
loopa:	add 	reg1, reg1, reg0
		cmp 	reg1, reg2
		bne		loopa
	}	
#endif

	/* Transmit the character */
	while (!(inpw(REG_UART_FSR+0x100) & 0x400000));
	outpb(REG_UART_THR+0x100, 'A');
	while (!(inpw(REG_UART_FSR+0x100) & 0x400000));

	/* Change the system clock souce to 12M crystal*/
	outp32(REG_CLKDIV0, (inp32(REG_CLKDIV0) & (~0x18)) );
#if defined (__GNUC__)
	__asm volatile
	(
		"  mov 	%0, #100       \n"
		"  mov  %1, #0         \n"
		"  mov  %2, #1         \n"
		" loop0:	           \n"
		"  add  %1, %1, %2     \n"
		"  cmp 	%1, %0         \n"
		"  bne  loop0          \n"
		: : "r"(reg2), "r"(reg1), "r"(reg0) :"memory"
	);
#else
	__asm
	{/* Dealy */
		mov 	reg2, #100
		mov		reg1, #0
		mov		reg0, #1
loop0:	add 	reg1, reg1, reg0
		cmp 	reg1, reg2
		bne		loop0
	}
#endif


	/* Transmit the character */
	while (!(inpw(REG_UART_FSR+0x100) & 0x400000));
	outpb(REG_UART_THR+0x100, 'B');
	while (!(inpw(REG_UART_FSR+0x100) & 0x400000));

	outp32(REG_UPLLCON, inp32(REG_UPLLCON) | 0x10000);		/* Power down UPLL and APLL */
	outp32(REG_APLLCON, inp32(REG_APLLCON) | 0x10000);		
	/* Transmit the character */
	while (!(inpw(REG_UART_FSR+0x100) & 0x400000));
	outpb(REG_UART_THR+0x100, 'C');
	while (!(inpw(REG_UART_FSR+0x100) & 0x400000));
#if defined (__GNUC__)
	__asm volatile
	(
		"  mov 	%0, #300      \n"
		"  mov  %1, #0         \n"
		"  mov  %2, #1         \n"
		" loop1:	           \n"
		"  add  %1, %1, %2     \n"
		"  cmp 	%1, %0         \n"
		"  bne  loop1          \n"
		: : "r"(reg2), "r"(reg1), "r"(reg0) :"memory"
	);
#else
	__asm
	{
		mov 	reg2, #300
		mov		reg1, #0
		mov		reg0, #1
loop1:	add 	reg1, reg1, reg0
		cmp 	reg1, reg2
		bne		loop1
	}	
#endif
	/* Fill and enable the pre-scale for power down wake up */
	outp32(REG_PWRCON, (inp32(REG_PWRCON)  & ~0xFFFF00) | 0xFFFF02);	

	/* Transmit the character */
	for(reg0 = 0; reg0<20; reg0=reg0+1)
	{
		while (!(inpw(REG_UART_FSR+0x100) & 0x400000));
		outpb(REG_UART_THR+0x100, 'D'+reg0);
		while (!(inpw(REG_UART_FSR+0x100) & 0x400000));
	}
#if defined (__GNUC__)
	/*
	__asm volatile
	(
		"  mov 	%0, #300      \n"
		"  mov  %1, #0         \n"
		"  mov  %2, #1         \n"
		" loop2:	           \n"
		"  add  %1, %1, %2     \n"
		"  cmp 	%1, %0         \n"
		"  bne  loop2          \n"
		: : "r"(reg2), "r"(reg1), "r"(reg0) :"memory"
	);
	*/
#else
	__asm
	{
		mov 	reg2, #10
		mov		reg1, #0
		mov		reg0, #1
loop2:	add 	reg1, reg1, reg0
		cmp 	reg1, reg2
		bne		loop2
	}
#endif

	/* Transmit the character */
	while (!(inpw(REG_UART_FSR+0x100) & 0x400000));
	outpb(REG_UART_THR+0x100, 'E');
	while (!(inpw(REG_UART_FSR+0x100) & 0x400000));

#if defined (__GNUC__)
	/*  Enter power down. (Stop the external clock */
	reg2 = 0xb0000200;
	__asm
	(
	 /* "  LDR 	 %0, %2         \n"   */
		"  ldmia %0,{%1}        \n"
		"  bic   %1, %1, #1     \n"
		"  stmia %0,{%1}        \n"
		: : "r"(reg2), "r"(reg1), "r"(reg0):
	 );

	__asm volatile
	(
		"  mov 	%0, #1000      \n"
		"  mov  %1, #0         \n"
		"  mov  %2, #1         \n"
		" loop3:	           \n"
		"  add  %1, %1, %2     \n"
		"  cmp 	%1, %0         \n"
		"  bne  loop3          \n"
		: : "r"(reg2), "r"(reg1), "r"(reg0) :"memory"
	);
#else
	/*  Enter power down. (Stop the external clock */
	__asm 
	{/* Power down */
		mov 	reg2, 0xb0000200
		ldmia 	reg2, {reg0}
		bic		reg0, reg0, #0x01
		stmia 	reg2, {reg0}
	}
	__asm
	{/* Wake up*/ 
		mov 	reg2, #1000
		mov		reg1, #0
		mov		reg0, #1
loop3:	add 	reg1, reg1, reg0
		cmp 	reg1, reg2
		bne		loop3
	}		
#endif


	 /* Force UPLL and APLL in normal mode */ 
	outp32(REG_UPLLCON, inp32(REG_UPLLCON) & (~0x10000));		
	outp32(REG_APLLCON, inp32(REG_APLLCON) & (~0x10000));	

#if defined(__GNUC__)
	__asm volatile
	(
		"  mov 	%0, #1000      \n"
		"  mov  %1, #0         \n"
		"  mov  %2, #1         \n"
		" loop4:	           \n"
		"  add  %1, %1, %2     \n"
		"  cmp 	%1, %0         \n"
		"  bne  loop4          \n"
		: : "r"(reg2), "r"(reg1), "r"(reg0) :"memory"
	);
#else
	__asm
	{/* Delay a moment for PLL stable */
			mov 	reg2, #1000
			mov		reg1, #0
			mov		reg0, #1
loop4:	    add 	reg1, reg1, reg0
			cmp 	reg1, reg2
			bne		loop4
	}		
#endif

	/* Change system clock to PLL and delay a moment.  Let DDR/SDRAM lock the frequency */
	outp32(REG_CLKDIV0, inp32(REG_CLKDIV0) | 0x18);	
#if defined(__GNUC__)
	__asm volatile
	(
		"  mov 	%0, #500       \n"
		"  mov  %1, #0         \n"
		"  mov  %2, #1         \n"
		" loop5:	           \n"
		"  add  %1, %1, %2     \n"
		"  cmp 	%1, %0         \n"
		"  bne  loop5          \n"
		: : "r"(reg2), "r"(reg1), "r"(reg0) :"memory"
	);
#else
	__asm
	{
			mov 	reg2, #500
			mov		reg1, #0
			mov		reg0, #1
loop5:		add 	reg1, reg1, reg0
			cmp 	reg1, reg2
			bne		loop5
	}
#endif
	/*Force DDR/SDRAM escape self-refresh */
	outp32(0xB0003004,  0x20);
#if defined(__GNUC__)
	__asm volatile
	(
		"  mov 	%0, #500      \n"
		"  mov  %1, #0         \n"
		"  mov  %2, #1         \n"
		" loop6:	           \n"
		"  add  %1, %1, %2     \n"
		"  cmp 	%1, %0         \n"
		"  bne  loop6          \n"
		: : "r"(reg2), "r"(reg1), "r"(reg0) :"memory"
	);
#else
	__asm
	{/*  Delay a moment until the escape self-refresh command reached to DDR/SDRAM */
			mov 	reg2, #500
			mov		reg1, #0
			mov		reg0, #1
	loop6:	add 	reg1, reg1, reg0
			cmp 	reg1, reg2
			bne		loop6
	}
#endif

}
INT32 Entry_PowerDown(void)
{
	UINT32 u32IntEnable;
	void (*wb_fun)(void);
#if 0
	UINT32 u32RamBase= 0xFF000000;
	UINT32 u32RamSize= 0x1000;
	BOOL bIsEnableIRQ = FALSE;
	memcpy((char*)(u32RamBase | 0x80000000), (char*)((UINT32)Sample_PowerDown | 0x80000000), u32RamSize);
	if(memcmp((char*)(u32RamBase | 0x80000000), (char*)((UINT32)Sample_PowerDown | 0x80000000), u32RamSize)!=0)
	{
		sysprintf("Memcpy copy wrong\n");
		return -1;
	}	
	if( sysGetIBitState()==TRUE )
	{
		bIsEnableIRQ = TRUE;
		sysSetLocalInterrupt(DISABLE_IRQ);
	}
#else
	UINT32 u32RamBase = PD_RAM_BASE;
	UINT32 u32RamSize = PD_RAM_SIZE;
	BOOL bIsEnableIRQ = FALSE;

	if( sysGetIBitState()==TRUE )
	{
		bIsEnableIRQ = TRUE;
		sysSetLocalInterrupt(DISABLE_IRQ);
	}
	//memcpy((char*)((UINT32)_tmp_buf| 0x80000000), (char*)(u32RamBase | 0x80000000), u32RamSize);
	memcpy((VOID *)((UINT32)u32RamBase | 0x80000000),
			(VOID *)( ((UINT32)Sample_PowerDown -(PD_RAM_START-PD_RAM_BASE)) | 0x80000000),
			PD_RAM_SIZE);
	if(memcmp((char*)(u32RamBase | 0x80000000), (char*)((UINT32)((UINT32)Sample_PowerDown -(PD_RAM_START-PD_RAM_BASE)) | 0x80000000), u32RamSize)!=0)
	{
		sysprintf("Memcpy copy wrong\n");
	}
	sysFlushCache(I_CACHE);
	//wb_fun = (void(*)(void)) u32RamBase;
	wb_fun = (void(*)(void))PD_RAM_START;
	sysprintf("Jump to SRAM (Suspend)\n");
#endif
	sysprintf("Jump to SRAM (Power down)\n");
	u32IntEnable = inp32(REG_AIC_IMR);	
	outp32(REG_AIC_MDCR, 0xFFFFFFFF);
	outp32(0xb0000030, 0x40400000);			/*  Enable the wake up interrupt channel. */
	wb_fun();
	outp32(0xb0000030, 0x40400000);			/*  Clear the wake up interrupt status */
	outp32(REG_AIC_MECR, u32IntEnable);	/*  Restore the interrupt channels */
	sysprintf("Exit to SRAM (Wake up)\n");
	if(bIsEnableIRQ==TRUE)
			sysSetLocalInterrupt(ENABLE_IRQ);
	return Successful;
}


void Smpl_TscPanel_WT_Powerdown_Wakeup(void)
{
	PFN_ADC_CALLBACK pfnOldCallback;
	UINT32 u32Count=1;
		
	adc_enableInt(eADC_WT_INT);
	  
	adc_installCallback(eADC_WT_INT,
							pfnWaitForTriggerCallback,
							&pfnOldCallback);
	adc_enableInt(eADC_ADC_INT);							
	adc_installCallback(eADC_ADC_INT,
							pfnRecordCallback,
							&pfnOldCallback);							
	outp32(REG_GPIOA_OMD, inp32(REG_GPIOA_OMD) | 0x01);	//GPIO output mode
	outp32(REG_GPIOA_PUEN, inp32(REG_GPIOA_PUEN) | 0x01);	//GPIO to high	
	outp32(REG_GPIOA_DOUT, inp32(REG_GPIOA_DOUT) | 0x01);	//GPIO to high	

	outp32(REG_GPBFUN, inp32(REG_GPBFUN) & ~3);
	outp32(REG_GPIOB_OMD, inp32(REG_GPIOB_OMD) | 0x01);	//GPIOB0 output mode
	outp32(REG_GPIOB_PUEN, inp32(REG_GPIOB_PUEN) | 0x01);	//GPIOB0 to high	
	outp32(REG_GPIOB_DOUT, inp32(REG_GPIOB_DOUT) | 0x01);	//GPIOB0 to high	

	while(1)
	{/* Power down wake up for test 30 times */										
		adc_setTouchScreen(eADC_TSCREEN_TRIG,	//E_DRVADC_TSC_MODE eTscMode,
							180,						//Delay cycle
							TRUE,					//BOOL bIsPullup,
							FALSE);					//BOOL bMAVFilter
		sysDelay(50);	
		sysprintf("\n");
		if(Entry_PowerDown()!=Successful)
		{
			sysprintf("Memory copy error \n");
			break;	
		}	
		outp32(0xb0000030, inp32(0xb0000030)| 0x40000000);	//Clear ADC wakeup status										
		sysprintf("Wake up!!! %d \n", u32Count);									
		u32Count = u32Count +1;
	}		
}