/****************************************************************************\
 *           Copyright (C) 2012 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 the features of GPIO on KeyStone device
 ****************************************************************************
 * Created by :                                                             *
 *            Brighton Feng                                                 *
 *            Texas Instruments                                             * 
 *            October 24, 2012                                              *
 *  August 24, 2013 Brighton Feng  Update for K2                            *
***************************************************************************/
#include <c6x.h>
#include <stdio.h>
#include <cslr_gpio.h>
#include <csl_bootcfgAux.h>
#include "K2_common.h"
#include "K2_board_init.h"

#define GPIO_LOOP_BACK_TEST 	1

#if defined(DEVICE_K2L)
Uint32 num_GPIO=64;
#else
Uint32 num_GPIO=32;
#endif

Uint16 usaCIC_GPIO_INT_table[]=
{
	CSL_CIC0_GPIO_INT16,
	CSL_CIC0_GPIO_INT17,
	CSL_CIC0_GPIO_INT18,
	CSL_CIC0_GPIO_INT19,
	CSL_CIC0_GPIO_INT20,
	CSL_CIC0_GPIO_INT21,
	CSL_CIC0_GPIO_INT22,
	CSL_CIC0_GPIO_INT23,
	CSL_CIC0_GPIO_INT24,
	CSL_CIC0_GPIO_INT25,
	CSL_CIC0_GPIO_INT26,
	CSL_CIC0_GPIO_INT27,
	CSL_CIC0_GPIO_INT28,
	CSL_CIC0_GPIO_INT29,
	CSL_CIC0_GPIO_INT30,
	CSL_CIC0_GPIO_INT31
#if defined(DEVICE_K2L)
	,
	CSL_CIC0_GPIO_INT32,
	CSL_CIC0_GPIO_INT33,
	CSL_CIC0_GPIO_INT34,
	CSL_CIC0_GPIO_INT35,
	CSL_CIC0_GPIO_INT36,
	CSL_CIC0_GPIO_INT37,
	CSL_CIC0_GPIO_INT38,
	CSL_CIC0_GPIO_INT39,
	CSL_CIC0_GPIO_INT40,
	CSL_CIC0_GPIO_INT41,
	CSL_CIC0_GPIO_INT42,
	CSL_CIC0_GPIO_INT43,
	CSL_CIC0_GPIO_INT44,
	CSL_CIC0_GPIO_INT45,
	CSL_CIC0_GPIO_INT46,
	CSL_CIC0_GPIO_INT47,
	CSL_CIC0_GPIO_INT48,
	CSL_CIC0_GPIO_INT49,
	CSL_CIC0_GPIO_INT50,
	CSL_CIC0_GPIO_INT51,
	CSL_CIC0_GPIO_INT52,
	CSL_CIC0_GPIO_INT53,
	CSL_CIC0_GPIO_INT54,
	CSL_CIC0_GPIO_INT55,
	CSL_CIC0_GPIO_INT56,
	CSL_CIC0_GPIO_INT57,
	CSL_CIC0_GPIO_INT58,
	CSL_CIC0_GPIO_INT59,
	CSL_CIC0_GPIO_INT60,
	CSL_CIC0_GPIO_INT61,
	CSL_CIC0_GPIO_INT62,
	CSL_CIC0_GPIO_INT63
#endif
};

Uint32 uiGPIO_host_event_num= 0;
void GPIO_Interrupts_Init(void)
{
	int i;
	
	/* Disable Global host interrupts. */
	gpCIC0_regs->GLOBAL_ENABLE_HINT_REG= 0;

	/*map GPIO Interrupt events higher than or equal 16 to same CIC0 out*/
	for(i=16; i<num_GPIO; i++)
	{
		KeyStone_CIC_event_map(gpCIC0_regs, usaCIC_GPIO_INT_table[i-16], uiGPIO_host_event_num);
	}

	/* Enable Global host interrupts. */
	gpCIC0_regs->GLOBAL_ENABLE_HINT_REG= 1;

	gpCGEM_regs->EVTMASK[0]= 	0xFFFFFFFF;
	gpCGEM_regs->EVTMASK[1]= 	0xFFFFFFFF;

	//combine GPIO interrupts 0~15 to INTC event 2 and 3
	gpCGEM_regs->EVTMASK[2]= ~((1<<(CSL_C66X_COREPAC_GPIO_INT8-32*2))|
		(1<<(CSL_C66X_COREPAC_GPIO_INT9-32*2))|
		(1<<(CSL_C66X_COREPAC_GPIO_INT10-32*2))|
		(1<<(CSL_C66X_COREPAC_GPIO_INT11-32*2))|
		(1<<(CSL_C66X_COREPAC_GPIO_INT12-32*2)));

#ifdef CSL_C66X_COREPAC_GPIO_INTN
	gpCGEM_regs->EVTMASK[3]= ~((1<<(CSL_C66X_COREPAC_GPIO_INTN%32))|
#else 	//for K2E
	gpCGEM_regs->EVTMASK[3]= ~((1<<(CSL_C66X_COREPAC_GPIO_INT0%32))|
#endif
		(1<<(CSL_C66X_COREPAC_GPIO_INT13-32*3))|
		(1<<(CSL_C66X_COREPAC_GPIO_INT14-32*3))|
		(1<<(CSL_C66X_COREPAC_GPIO_INT15-32*3)));

	gpCGEM_regs->INTMUX1 = 0;
	gpCGEM_regs->INTMUX2 = 0;

	//map GPIO events to INT13~15
	gpCGEM_regs->INTMUX3 = (CSL_C66X_COREPAC_EVT2<<CSL_CGEM_INTMUX3_INTSEL13_SHIFT)
		|(CSL_C66X_COREPAC_EVT3<<CSL_CGEM_INTMUX3_INTSEL14_SHIFT)
#ifdef CSL_C66X_COREPAC_CIC_OUT0
		|(CSL_C66X_COREPAC_CIC_OUT0<<CSL_CGEM_INTMUX3_INTSEL15_SHIFT);
#else
		|(CSL_C66X_COREPAC_CIC_0_OUT0<<CSL_CGEM_INTMUX3_INTSEL15_SHIFT);
#endif

	//enable INT13~15
	CPU_interrupt_enable((1<<13)|(1<<14)|(1<<15));
}

void GPIO_init(Uint32 uiGPIO_instant_num)
{
	CSL_GpioRegs * GPIO_regs;

#if defined(DEVICE_K2L)
	if(uiGPIO_instant_num>0) 	//for K2L
	{
		CSL_BootCfgUnlockKicker();
		//GPIO 32~63 MUX with other interface, here we set them as GPIO pins.
		gpBootCfgRegs->PIN_MUXCTL2= 0xFFFFFFFF;
	}
#endif

#if defined(DEVICE_K2L)
	if(uiGPIO_instant_num>0) 	//for K2L
	{
		GPIO_regs= gpGPIO1_regs;
	}
	else
#endif
	{
		GPIO_regs= gpGPIO_regs;
	}

	/*set GPIO direction*/
#if GPIO_LOOP_BACK_TEST
	/*When the GPIO pin is configured as output, software can toggle the 
	GPIO output register to change the pin state and in turn trigger the 
	interrupt and EDMA event.*/
	GPIO_regs->BANK_REGISTERS[0].DIR= 0;
#else
	GPIO_regs->BANK_REGISTERS[0].DIR= 0xFFFFFFFF;
#endif

	/*enable interrupt*/
	GPIO_regs->BINTEN= 0x3;

	/*trigger interrupt on both rising and falling edge*/	
	GPIO_regs->BANK_REGISTERS[0].SET_RIS_TRIG= 0xFFFFFFFF;
	GPIO_regs->BANK_REGISTERS[0].SET_FAL_TRIG= 0xFFFFFFFF;

	/*clear output data*/
	GPIO_regs->BANK_REGISTERS[0].CLR_DATA= 0xFFFFFFFF;

}

void check_GPIO()
{
	printf("GPIO IN_DATA= ");
#if defined(DEVICE_K2L)
	printf("0x%08x ",gpGPIO1_regs->BANK_REGISTERS[0].IN_DATA);
#endif
	printf("0x%08x\n",gpGPIO_regs->BANK_REGISTERS[0].IN_DATA);
}

void GPIO_loopback_test()
{
	int i;

	/*toggle all GPIOs*/
	for(i=12; i<16; i++)	// 0 ~ num_GPIO
	{
		if(i<32)
		{
			gpGPIO_regs->BANK_REGISTERS[0].SET_DATA= (1<<i);
			TSC_delay_ms(1);
			check_GPIO();

			gpGPIO_regs->BANK_REGISTERS[0].CLR_DATA= (1<<i);
			TSC_delay_ms(1);
			check_GPIO();
		}
#if defined(DEVICE_K2L)
		else
		{
			gpGPIO1_regs->BANK_REGISTERS[0].SET_DATA= (1<<(i-32));
			TSC_delay_ms(1);
			check_GPIO();

			gpGPIO1_regs->BANK_REGISTERS[0].CLR_DATA= (1<<(i-32));
			TSC_delay_ms(1);
			check_GPIO();
		}
#endif

		printf("\n");
	}
}

void main()
{
    CACHE_setL1PSize(CACHE_L1_32KCACHE);
    CACHE_setL1DSize(CACHE_L1_32KCACHE);
    CACHE_setL2Size(CACHE_0KCACHE);

	//enable TSC, memory protection interrupts, EDC for internal RAM; clear cache; protect L1 as cache
	KeyStone_common_CPU_init();
	K2_common_device_init();

	//Main 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);

	GPIO_init(0);
#if defined(DEVICE_K2L)
	GPIO_init(1);
#endif

	GPIO_Interrupts_Init();

	//enable exception handling
	KeyStone_Exception_cfg(TRUE);

#if GPIO_LOOP_BACK_TEST
	while (1)
		GPIO_loopback_test();
#else
	while(1)
	{
		check_GPIO();	
		TSC_delay_ms(1000);
	};
#endif

	puts("GPIO Test complete.");
}

void GPIO_print_interrupt_status(Uint32 uiEventFlag)
{
	int i;
	for(i=0; i<32; i++)
	{
		if((uiEventFlag>>i)&1)
			printf("GPIO %d interrupt happened.\n", i);
	}
}

//Interrupt service routine for local GPIO and GPIO 13~15
void interrupt GPIO_ISR(void)
{
	Uint32 eventFlag;

	/*read interrupt flag*/
	eventFlag= gpCGEM_regs->MEVTFLAG[3];

	/*clear interrupt flag*/
	gpCGEM_regs->EVTCLR[3]= eventFlag;

#ifdef CSL_C66X_COREPAC_GPIO_INTN
	eventFlag= ((eventFlag&(~(1<<(CSL_C66X_COREPAC_GPIO_INTN%32))))<<(7))
		|((eventFlag>>(CSL_C66X_COREPAC_GPIO_INTN%32))<<DNUM);
#else //for K2E
	eventFlag= ((eventFlag&(~(1<<(CSL_C66X_COREPAC_GPIO_INT0%32))))<<(7))
		|((eventFlag>>(CSL_C66X_COREPAC_GPIO_INT0%32))<<DNUM);
#endif
	GPIO_print_interrupt_status(eventFlag);
}

//Interrupt service routine for GPIO 8~12
void interrupt GPIO_8_12_ISR(void)
{
	Uint32 eventFlag;

	/*read interrupt flag*/
	eventFlag= gpCGEM_regs->MEVTFLAG[2];

	/*clear interrupt flag*/
	gpCGEM_regs->EVTCLR[2]= eventFlag;

	GPIO_print_interrupt_status(eventFlag>>10);
}

//Interrupt service routine for GPIO equal or higher 16
void interrupt GPIO_16_up_ISR(void)
{
	int i;
	Uint32 uiRegIndex, uiBitInex;
	
	/* Disable the host interrupt */
	gpCIC0_regs->HINT_ENABLE_CLR_INDEX_REG = uiGPIO_host_event_num;

	for(i=16; i<num_GPIO; i++)
	{
		uiRegIndex= usaCIC_GPIO_INT_table[i-16]/32;
		uiBitInex= usaCIC_GPIO_INT_table[i-16]%32;

		if(gpCIC0_regs->ENA_STATUS_REG[uiRegIndex]&(1<<uiBitInex))
		{
			/* Clear GPIO Interrupt event in CIC*/
			KeyStone_CIC_clear_system_event(gpCIC0_regs, usaCIC_GPIO_INT_table[i-16]);

			printf("GPIO %d interrupt happened.\n", i);
		}
	}

	/* Enable the host interrupt */
	gpCIC0_regs->HINT_ENABLE_SET_INDEX_REG = uiGPIO_host_event_num;
}


