/******************************************************************************

  Copyright (C), 2013, Texas Instrument.

 ******************************************************************************
  File Name     : UART_Interrupt.c
  Version       : Initial Draft
  Author        : Vincent Han
  Created       : 2013/5/17
  Last Modified :
  Description   :  UART interrupt setup and handling 

  History       :
  1.Date        : May 17, 2013
    Author      : Vincent Han
    Modification: Created file for KeyStone 2
  2.Date        : July 27, 2013
    Author      : Brighton Feng
    Modification: code clean up

******************************************************************************/

#include <stdio.h>
#include <ti/csl/csl_bootcfg.h>
#include <ti/csl/csl_bootcfgAux.h>
#include <ti/csl/csl_cpintc.h>
#include <K2_common.h>
#include <K2_UART_Init_drv.h>
#include "UART_interrupt.h"

//RX buffer used by RX interrupt
/* Need to be the same with Rx FIFO trigger level size */
unsigned char UART_Rx_Buf[RX_BUF_BYTE_SIZE] __attribute__ ((aligned (16))); 

volatile Bool bUartEchoBack; //Echo the received data back

unsigned char UART_Echo_Buf[2*RX_BUF_BYTE_SIZE] __attribute__ ((aligned (16))); 

//echo back the received characters
void UART_Echo_back(Uint32 rx_cnt, Uint32 uartNum)
{
	Uint32 echo_cnt=0, i;
	
    for (i = 0; i < rx_cnt; i++)
    {
        printf("%c", UART_Rx_Buf[i]);
    }
    fflush(stdout);

	//copy the data from RX buffer to TX buffer for echo back
	for(i = 0; i < rx_cnt; i++)
	{
		UART_Echo_Buf[echo_cnt++]= UART_Rx_Buf[i];
        if((UART_Rx_Buf[i] == 13)&& (UART_Rx_Buf[i+1] != 13)) 	//return without new line
        {
            UART_Echo_Buf[echo_cnt++] = 10; 	//add new line after return
        }
	}

	//write back the characters
    K2_UART_write(UART_Echo_Buf, echo_cnt, uartNum);
}

void K2_UART_Rx_ISR(Uint32 uiIAR_value, Uint32 uiIntAddress)
{
	Uint32 uiUartNum, uiINT_ID, rx_cnt;

	uiINT_ID= GIC_GET_INT_ID(uiIAR_value)-32;

	if(uiINT_ID==CSL_ARM_GIC_UART_0_URXEVT)
		uiUartNum=CSL_UART_0;
	else if(uiINT_ID==CSL_ARM_GIC_UART_1_URXEVT)
		uiUartNum=CSL_UART_1;
#ifdef CSL_UART_2 	//K2L only
	else if(uiINT_ID==CSL_ARM_GIC_UART_2_URXEVT)
		uiUartNum=CSL_UART_2;
#endif
#ifdef CSL_UART_3 	//K2L only
	else if(uiINT_ID==CSL_ARM_GIC_UART_3_URXEVT)
		uiUartNum=CSL_UART_3;
#endif
	else
	{
		printf("UART RX ISR was triggered with invalid interrupt ID, IAR value= 0x%x\n", uiIAR_value);
		return;
	}

	rx_cnt= KeyStone_UART_read(UART_Rx_Buf, RX_BUF_BYTE_SIZE, uiUartNum);

	//echo back the received characters
	if(bUartEchoBack)
		UART_Echo_back(rx_cnt, uiUartNum);
}

void K2_UART_Error_ISR(Uint32 uiIAR_value, Uint32 uiIntAddress)
{
	Uint32 uiINT_ID;

	uiINT_ID= GIC_GET_INT_ID(uiIAR_value)-32;

	if(uiINT_ID==CSL_ARM_GIC_UART_0_UARTINT)
		KeyStone_UART_Error_Handler(CSL_UART_0);
	else if(uiINT_ID==CSL_ARM_GIC_UART_1_UARTINT)
		KeyStone_UART_Error_Handler(CSL_UART_1);
#ifdef CSL_UART_2 	//K2L only
	else if(uiINT_ID==CSL_ARM_GIC_UART_2_UARTINT)
		KeyStone_UART_Error_Handler(CSL_UART_2);
#endif
#ifdef CSL_UART_3 	//K2L only
	else if(uiINT_ID==CSL_ARM_GIC_UART_3_UARTINT)
		KeyStone_UART_Error_Handler(CSL_UART_3);
#endif
	else
	{
		printf("UART Error ISR was triggered with invalid interrupt ID, IAR value= 0x%x\n", uiIAR_value);
	}
}

void UART_EDMA_complete_handler(Uint32 tpccNum)
{
	Uint32 IPR, IPRH;
	
	IPRH = gpEDMA_CC_regs[tpccNum]->TPCC_IPRH;
    IPR  = gpEDMA_CC_regs[tpccNum]->TPCC_IPR;

	//disable event to avoid EDMA event miss error
	gpEDMA_CC_regs[tpccNum]->TPCC_EECRH= IPRH;
    gpEDMA_CC_regs[tpccNum]->TPCC_EECR = IPR;

	//clear interrupt
	gpEDMA_CC_regs[tpccNum]->TPCC_ICRH= IPRH;
    gpEDMA_CC_regs[tpccNum]->TPCC_ICR = IPR;

	printf("EDMA CC%d for UART transfer complete.\n", tpccNum);
            
    gpEDMA_CC_regs[tpccNum]->TPCC_IEVAL = 1;

}

/****************** Process for EDMA Tx Interrupt *******************/
void K2_UART_EDMA_ISR(Uint32 uiIAR_value, Uint32 uiIntAddress)
{
	Uint32 uiINT_ID;

	uiINT_ID= GIC_GET_INT_ID(uiIAR_value)-32;

	if(uiINT_ID==CSL_ARM_GIC_EDMACC_2_GINT)
		UART_EDMA_complete_handler(2);
#ifndef DEVICE_K2L 	//K2L only use EDMA CC2 for UART
	else if(uiINT_ID==CSL_ARM_GIC_EDMACC_3_GINT)
		UART_EDMA_complete_handler(3);
#endif
	else
	{
		printf("UART EDMA ISR was triggered with invalid interrupt ID, IAR value= 0x%x\n", uiIAR_value);
	}
}

void K2_UART_Interrupts_Init(Bool bRxIntEnable, Bool bEDMAInterruptEnable)
{
	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;

	if(bRxIntEnable)
	{
		GIC_interrupt_hook(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_UART_0_URXEVT), &int_cfg, K2_UART_Rx_ISR);
		GIC_interrupt_hook(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_UART_1_URXEVT), &int_cfg, K2_UART_Rx_ISR);
#ifdef CSL_UART_2 	//K2L only
		GIC_interrupt_hook(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_UART_2_URXEVT), &int_cfg, K2_UART_Rx_ISR);
#endif
#ifdef CSL_UART_3 	//K2L only
		GIC_interrupt_hook(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_UART_3_URXEVT), &int_cfg, K2_UART_Rx_ISR);
#endif
	}
	else
	{
		GIC_interupt_disable(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_UART_0_URXEVT));
		GIC_interupt_disable(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_UART_1_URXEVT));
#ifdef CSL_UART_2 	//K2L only
		GIC_interupt_disable(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_UART_2_URXEVT));
#endif
#ifdef CSL_UART_3 	//K2L only
		GIC_interupt_disable(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_UART_3_URXEVT));
#endif
	}
	
	GIC_interrupt_hook(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_UART_0_UARTINT), &int_cfg, K2_UART_Error_ISR);
	GIC_interrupt_hook(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_UART_1_UARTINT), &int_cfg, K2_UART_Error_ISR);
#ifdef CSL_UART_2 	//K2L only
	GIC_interrupt_hook(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_UART_2_UARTINT), &int_cfg, K2_UART_Error_ISR);
#endif
#ifdef CSL_UART_3 	//K2L only
	GIC_interrupt_hook(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_UART_3_UARTINT), &int_cfg, K2_UART_Error_ISR);
#endif

	if(bEDMAInterruptEnable)
	{
		GIC_interrupt_hook(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_EDMACC_2_GINT), &int_cfg, K2_UART_EDMA_ISR);
#ifndef DEVICE_K2L
		GIC_interrupt_hook(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_EDMACC_3_GINT), &int_cfg, K2_UART_EDMA_ISR);
#endif
	}
	else
	{
		GIC_interupt_disable(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_EDMACC_2_GINT));
#ifndef DEVICE_K2L
		GIC_interupt_disable(GIC_CONVERT_SPI_ID(CSL_ARM_GIC_EDMACC_3_GINT));
#endif
	}
}

