/****************************************************************************\
 *           Copyright (C) 2013 Texas Instruments Incorporated.             *
 *                           All Rights Reserved                            *
 *                                                                          *
 * GENERAL DISCLAIMER                                                       *
 * ------------------                                                       *
 * All software and related documentation is provided "AS IS" and without   *
 * warranty or support of any kind and Texas Instruments expressly disclaims*
 * all other warranties, express or implied, including, but not limited to, *
 * the implied warranties of merchantability and fitness for a particular   *
 * purpose.  Under no circumstances shall Texas Instruments be liable for   *
 * any incidental, special or consequential damages that result from the    *
 * use or inability to use the software or related documentation, even if   *
 * Texas Instruments has been advised of the liability.                     *
 ****************************************************************************
This example shows three main features of Timers on KeyStone DSP:
1. generate one-shot pulse and interrupt
2. generate continual clock and interrupts
3. watch-dog
 ****************************************************************************
 * Created by :                                                             *
 *            Brighton Feng                                                 *
 *            Texas Instruments                                             * 
 *            March 5, 2012                                                 *
 * Updated by Brighton on Feb 8, 2013 for K2                                *
***************************************************************************/
#include <c6x.h>
#include <stdio.h>
#include <csl_bootcfgAux.h>
#include "K2_common.h"
#include "K2_Board_Init.h"

/*delay (in millisecond) before the timer generate one-shot pulse*/
#define PULSE_DELAY_MS 			2000
/*period (in millisecond) of the clock generated by timer*/
#define CLOCK_PERIOD_MS 		1
/*number of the clocks generated in this test*/
#define NUM_CLOCKS_GENERATED 	500
/*period (in millisecond) of the watch-dog timer*/
#define WATCH_DOG_PERIOD_MS 	3000

/*since the timer runs at (DSP core clock)/6
the conversion between millisecond and timer PRD value is:
PRD = (xxx_MS/1000)*DSP_CLK_HZ/6
    = xxx_MS*(DSP_CLK_HZ/1000)/6
    = xxx_MS*DSP_CLK_KHZ/6*/
    
volatile Uint32 uiTick = 0;

void Timer_Interrupts_Init(void)
{
	gCGEM_Regs->INTMUX1 = 0;
	gCGEM_Regs->INTMUX2 = 0;
	//map local timer interrupt to INT14
	gCGEM_Regs->INTMUX3 = CSL_C66X_COREPAC_TIMER_N_INTL<<CSL_CGEM_INTMUX3_INTSEL14_SHIFT;

	 /*Clear all DSP core events*/
	gCGEM_Regs->EVTCLR[0]= 	0xFFFFFFFF;
	gCGEM_Regs->EVTCLR[1]= 	0xFFFFFFFF;
	gCGEM_Regs->EVTCLR[2]= 	0xFFFFFFFF;
	gCGEM_Regs->EVTCLR[3]= 	0xFFFFFFFF;

	//clear DSP core interrupt flag
	ICR= IFR;

	//enable INT14
	IER = IER|(1<<14);

	/*Interrupt Service Table Pointer to begining of LL2 memory*/
	ISTP= 0x800000;

	//enable GIE
	TSR = TSR|1;
}

//Interrupt service routine for timer
void interrupt Timer_ISR(void)
{
	uiTick++;
}

/*use local timer (==DNUM of a core) to generate a pulse on TIMO0,
a interrupt is generated as well*/
void generate_pulse_by_timer()
{
	Timer64_Config tmrCfg;
	
	puts("\na pulse will be generated on TIMO0...");

	uiTick = 0;

	//select output on TIMO0 from local timer.
	gBootCfgRegs->TOUTSEL = (DNUM*2)<<CSL_BOOTCFG_TOUTSEL_TOUTSEL0_SHIFT;

	//configure the timer for one shot pulse
	tmrCfg.timer_num= DNUM;
	tmrCfg.timerMode= TIMER_ONE_SHOT_PULSE;
	tmrCfg.period= (unsigned long long)PULSE_DELAY_MS*gDSP_Core_Speed_Hz/1000/6;
	tmrCfg.pulseWidth= 3;
	Timer64_Init(&tmrCfg);

	//wait until the interrupt happen, which means the pulse has been generated
	while(0==uiTick)
		asm(" nop 5");

	puts("a pulse was generated on TIMO0\n");
}

/*use local timer (==DNUM of a core) to generate a clock on TIMO0,
interrupts are generated as well*/
void generate_clocks_by_timer()
{
	Timer64_Config tmrCfg;

	puts("clocks will be generated on TIMO0...");

	uiTick = 0;

	//select output on TIMO0 from local timer.
	gBootCfgRegs->TOUTSEL = (DNUM*2)<<CSL_BOOTCFG_TOUTSEL_TOUTSEL0_SHIFT;

	/*configure the timer to generate clocks and interrupts*/
	tmrCfg.timer_num= DNUM;
	tmrCfg.timerMode= TIMER_PERIODIC_CLOCK;
	tmrCfg.period= (unsigned long long)CLOCK_PERIOD_MS*gDSP_Core_Speed_Hz/1000/6;
	Timer64_Init(&tmrCfg);

	//wait until a number of interupts happen
	while(uiTick<NUM_CLOCKS_GENERATED*2)
		asm(" nop 5");
	Reset_Timer(DNUM); 	//stop the timer
	
	puts("clocks were generated on TIMO0\n");
}

/*set local timer (==DNUM of a core) as watch dog timer,
service the watch-dog for sometime, 
after stop servicing watch-dog, let it trigger NMI*/
void watchdog_timer_test()
{
	int i;
	Uint32 timerCnt;
	Timer64_Config tmrCfg;

	//select output on TIMO0 from local timer.
	gBootCfgRegs->TOUTSEL = (DNUM*2)<<CSL_BOOTCFG_TOUTSEL_TOUTSEL0_SHIFT;

	gBootCfgRegs->RSTMUX[DNUM] = 
		(4<<CSL_BOOTCFG_RSTMUX0_RSTMUX_DELAY0_SHIFT)
		/*WD timer event trigger NMI*/
		|(WD_TRIGGER_NMI<<CSL_BOOTCFG_RSTMUX0_RSTMUX_OMODE0_SHIFT);

	puts("start watch-dog timer...");

	//configure the timer for watch-dog
	tmrCfg.timer_num= DNUM;
	tmrCfg.timerMode= TIMER_WATCH_DOG;
	tmrCfg.period= (unsigned long long)WATCH_DOG_PERIOD_MS*gDSP_Core_Speed_Hz/1000/6;
	tmrCfg.pulseWidth= 3;
	Timer64_Init(&tmrCfg);

	//service the watch-dog for sometime, 
	for(i=1; i<=30; i++)
	{
		timerCnt= gTimerRegs[DNUM]->CNTLO;
		Service_Watchdog(DNUM);
		printf("service watch-dog %d times, at time counter = %u\n", 
			i, timerCnt);
	}

	puts("stop servicing watch-dog, it will timeout and trigger NMI...\n");
}

void main()
{

    CACHE_setL1PSize(CACHE_L1_32KCACHE);
    CACHE_setL1DSize(CACHE_L1_32KCACHE);
    CACHE_setL2Size(CACHE_0KCACHE);
	CACHE_invAllL1p(CACHE_WAIT);
	CACHE_wbInvAllL1d(CACHE_WAIT);

	CSL_BootCfgUnlockKicker();

	//DSP core speed= MAIN_PLL_REF_CLK_MHZ*MAIN_PLL_MULTIPLIER/MAIN_PLL_DIVISOR
	KeyStone_main_PLL_init(MAIN_PLL_REF_CLK_MHZ, MAIN_PLL_MULTIPLIER, MAIN_PLL_DIVISOR);

	Timer_Interrupts_Init();

	/* protect L1 as cache */
   	L1_cache_protection();

	/*enable L1P ED and scrub whole L1P*/
	L1P_EDC_setup();

   	/*enable LL2 EDC and scrub whole LL2*/
	LL2_EDC_setup();

	/*Enable MSMC EDC and setup scrubbing cycle counter= 255*1024*/
	KeyStone_SL2_EDC_enable(255);

   	/*exception configuration, also configure event 23 as the CIC exception input*/
	KeyStone_Exception_cfg();

	generate_pulse_by_timer();
	generate_clocks_by_timer();
	watchdog_timer_test();

	while(1);
}

