/****************************************************************************\
 *           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 <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

//MMU memory ranges tables
MMU_Memory_Map_Range memory_ranges[]=
{
	{//MSMC RAM
    .uiVirtualAddress   = 0x0C000000,
    .ullPhysicalAddress = 0x0C000000,
    .uiByteCnt          = MSMC_RAM_SIZE_BYTES,
    .attribute          = MMU_MEM_ATTR_NORMAL_CACHE_RA_WB_WA,
    .accessPermission   = MMU_MEM_ATTR_RW,
    .exectuePermission  = MMU_MEM_ATTR_X,
    .shareAttr          = MMU_MEM_ATTR_OUTER_SHARE,
    .isGlobal           = MMU_MEM_ATTR_GLOBAL,
    .isSecure           = MMU_MEM_ATTR_SECURE,
	},                     
	{//DDR3A               
    .uiVirtualAddress   = 0x80000000,
    .ullPhysicalAddress = 0x800000000ULL, 	
#if (DDR3A_SIZE_BYTES>0x80000000ULL)
    .uiByteCnt          = 0x80000000, 	
#else
    .uiByteCnt          = DDR3A_SIZE_BYTES, 	
#endif
    .attribute          = MMU_MEM_ATTR_NORMAL_CACHE_RA_WB_WA,
    .accessPermission   = MMU_MEM_ATTR_RW,
    .exectuePermission  = MMU_MEM_ATTR_XN,
    .shareAttr          = MMU_MEM_ATTR_OUTER_SHARE,
    .isGlobal           = MMU_MEM_ATTR_GLOBAL,
    .isSecure           = MMU_MEM_ATTR_SECURE,
	}
};

MMU_Long_Format_Config mmu_cfg=
{
	.memory_map        = memory_ranges,
	.uiNumMemMapRanges = sizeof(memory_ranges)/sizeof(MMU_Memory_Map_Range),
	.ullpMMU3rdLevelTT = NULL, 	//No level 3 translation table
	.bAlignCheck       = TRUE,
	.tableCacheAttr    = MMU_TAB_ATTR_CACHE_WB_WA,
	.tableShareAttr	   = MMU_MEM_ATTR_INNER_SHARE,
};

void GPIO_ISR(Uint32 uiIAR_value, Uint32 uiIntAddress)
{
	Uint32 uiGpioNum=65, uiINT_ID;

	uiINT_ID= GIC_GET_INT_ID(uiIAR_value)-32;

	if((uiINT_ID>=CSL_ARM_GIC_GPIO_INT0)&&(uiINT_ID<=CSL_ARM_GIC_GPIO_INT31))
		uiGpioNum= uiINT_ID-CSL_ARM_GIC_GPIO_INT0;

#ifdef DEVICE_K2L
	if((uiINT_ID>=CSL_ARM_GIC_GPIO_INT32)&&(uiINT_ID<=CSL_ARM_GIC_GPIO_INT56))
		uiGpioNum= uiINT_ID-CSL_ARM_GIC_GPIO_INT32+32;
	if((uiINT_ID>=CSL_ARM_GIC_GPIO_INT57)&&(uiINT_ID<=CSL_ARM_GIC_GPIO_INT63))
		uiGpioNum= uiINT_ID-CSL_ARM_GIC_GPIO_INT57+57;
#endif		

	if(65==uiGpioNum)
	{
		printf("GPIO ISR was triggered with invalid interrupt ID, IAR value= 0x%x\n", uiIAR_value);
	}
	else 
	{
		printf("GPIO %d interrupt happens.\n", uiGpioNum);
	}
}

void GPIO_Interrupts_Init(void)
{
	int i;
	GIC_INT_Config int_cfg;

	int_cfg.trigger_type= GIC_TRIGGER_TYPE_EDGE;
	int_cfg.ucGroupNum= 1; //route to group 1, IRQ
	int_cfg.ucPriority= GIC400_PRIORITY_LOWEST;

	for(i=CSL_ARM_GIC_GPIO_INT0; i<=CSL_ARM_GIC_GPIO_INT31; i++)
	{
		GIC_interrupt_hook(GIC_CONVERT_SPI_ID(i), &int_cfg, GPIO_ISR);
	}


#ifdef DEVICE_K2L
	for(i=CSL_ARM_GIC_GPIO_INT32; i<=CSL_ARM_GIC_GPIO_INT56; i++)
	{
		GIC_interrupt_hook(GIC_CONVERT_SPI_ID(i), &int_cfg, GPIO_ISR);
	}

	for(i=CSL_ARM_GIC_GPIO_INT57; i<=CSL_ARM_GIC_GPIO_INT63; i++)
	{
		GIC_interrupt_hook(GIC_CONVERT_SPI_ID(i), &int_cfg, GPIO_ISR);
	}

#endif
}

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=0; i<num_GPIO; i++)
	{
		if(i<32)
		{
			gpGPIO_regs->BANK_REGISTERS[0].SET_DATA= (1<<i);
			delay_ms(100);
			check_GPIO();

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

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

		printf("\n");
	}
}

int main()
{
	/*common initialization for internal modules in K2 device 
	enable GIC, memory protection interrupts, EDC for MSMC RAM */
	K2_common_device_init();
	/*initialize GIC interface for CPU, enable IRQ, FIQ, PMU*/
	K2_common_CPU_init();
	KeyStone_Exception_cfg(TRUE);

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

#ifndef DEVICE_K2E 	//K2E only has main PLL for both ARM and DSP cores
	//ARM core speed= ARM_PLL_REF_CLK_MHZ*ARM_PLL_MULTIPLIER/ARM_PLL_DIVISOR
	K2_ARM_PLL_init(ARM_PLL_REF_CLK_MHZ, ARM_PLL_MULTIPLIER, ARM_PLL_DIVISOR);
	//K2_ARM_PLL_init(125, 8, 1);
#endif

	/*MMU configure for ARM core*/
	MMU_long_format_init(&mmu_cfg);
	CP15_ICacheEnable();
	CP15_DCacheEnable();

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

	GPIO_Interrupts_Init();

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

	puts("GPIO Test complete.");
	return 0;
}

