/**
 * \file   plat_utils.c
 *
 * \brief  
 *
 * 
*/

/*
 * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
 */

/* ========================================================================== */
/*                             Include Files                                  */
/* ========================================================================== */
#include "string.h"

#include "hw/hw_types.h"
#include "hw_cm_per.h"
#include <hw/soc_AM335x.h>
#include "hw_control_AM335x.h"
#include <mcspi.h>
#include "gpio.h"
#include "plat_utils.h"
#include "plat_mcspi.h"
#include "plat_delay.h"
#include "plat_i2c.h"


/* ========================================================================== */
/*                           Macros & Typedefs                                */
/* ========================================================================== */

/* ========================================================================== */
/*                         Structures and Enums                               */
/* ========================================================================== */

/* ========================================================================== */
/*                 Internal Function Declarations                             */
/* ========================================================================== */ 
/**
 * \brief   ICSS PRCM Enable step 1
 *
 * \param   None
 *
 *
 * \return  None
 *
 **/ 
void UTILsICSSPRCMEnableStep1(void);

/**
 * \brief   Reset ICSS
 *
 * \param   None
 *
 *
 * \return  None
 *
 **/ 
void UTILsICSSPRCMReset(void);
/* ========================================================================== */
/*                            Global Variables                                */
/* ========================================================================== */
/**
 *   Varaible to store board type - 
 *   NOTE - Here board type is set to ICE as default, as many of the 
 *         ICE boards are having non-programmed EEPROMs. 
 */
volatile unsigned char am335x_board_type = AM335X_BOARD_TYPE_ICE;

// Spi Rx Data Struct for HVS882
unsigned short rx_data_hvs;					

static char* dev_names[] = 
{
    "AM3352",
    "AM3354",
    "AM3356",
    "AM3357",
    "AM3358",
    "AM3359",
    "Unknown"
};

static char* chip_ver_name[] = 
{
    "AM335x ES1.0 [PG1]",
    "AM335x ES1.1 [PG2]",
	"AM335x ES1.2 [PG2.1]",
    "Unknown"
};

/* ========================================================================== */
/*                          Function Definitions                              */
/* ========================================================================== */

char * UTILsGetDevName()
{
    //Return Device name - in String format
    unsigned int temp = *((unsigned int*) 0x44E10604);
    
    switch(temp)
    {
        case 0x00FC0382: 
            return dev_names[0];
        case 0x20FC0382: 
            return dev_names[1];
        case 0x00FD0383: 
            return dev_names[2];
        case 0x00FF0383: 
            return dev_names[3];
        case 0x20FD0383: 
            return dev_names[4];
        case 0x20FF0383: 
            return dev_names[5];
        default :
            return dev_names[6];
    }
}

char * UTILsGetChipRevision()
{
    //Return Device name - in String format
    unsigned int temp = *((unsigned int*) 0x44E10600);
    temp = (temp >> 28) & 0xF;
    switch(temp)
    {
        case 0: 
        case 1: 
        case 2: 
            return chip_ver_name[temp];			
        default :
			return chip_ver_name[(sizeof(chip_ver_name)/sizeof(char*)) - 1];
    }
}

unsigned int UTILsGetArmClockRate()
{
    //Return ARM frequency 

    unsigned int temp = *((unsigned int*) 0x44e0042c);
    return ((temp >> 8 ) & 0x3FF);
}

unsigned short UTILsReadHVS(void)
{
    unsigned char tx_data[10];					// Spi Tx Data Struct
    volatile unsigned int loop = 0;
	if(AM335X_BOARD_TYPE_ICE == am335x_board_type )
	{
		/* Toggle GPIO for HVS882 input load pulse (low active)*/
        GPIOPinWrite(SOC_GPIO_3_REGS, 18,0);
        for(loop = 0; loop < 500; loop++);
        GPIOPinWrite(SOC_GPIO_3_REGS, 18,1);

		tx_data[0] = 0;
        McSPICycle(MCSPI_INST_HVS882_ICE,tx_data,1,MCSPI_HVS882_CH_ICE);// 1 word read from HVS input
        rx_data_hvs = tx_data[0];
	}
    else if(AM335X_BOARD_TYPE_ICE_V2 == am335x_board_type )
    {
        tx_data[0] = 0;
        
        McSPICycle(MCSPI_INST_HVS882_ICE_V2, tx_data, 1, MCSPI_HVS882_CH_ICE_V2);
        
        /* Toggle GPIO for HVS882 input load pulse (low active)*/
        GPIOPinWrite(SOC_GPIO_3_REGS, 18,0);
        for(loop = 0; loop < 500; loop++);
        GPIOPinWrite(SOC_GPIO_3_REGS, 18,1);
        McSPICycle(MCSPI_INST_HVS882_ICE_V2, tx_data, 1, MCSPI_HVS882_CH_ICE_V2);
        rx_data_hvs = (unsigned short)(tx_data[0] & 0x7F);
    }
    else if(AM335X_BOARD_TYPE_IDK == am335x_board_type)
    {
        McSPICycle(MCSPI_INST_HVS882_IDK, tx_data, 1, MCSPI_HVS882_CH_IDK);
    
        GPIOPinWrite(SOC_GPIO_0_REGS, 13,0);
        for(loop = 0; loop < 500; loop++);
        GPIOPinWrite(SOC_GPIO_0_REGS, 13,1);
        
        for(loop = 0; loop < 500; loop++);
        GPIOPinWrite(SOC_GPIO_1_REGS, 9,0);
        GPIOPinWrite(SOC_GPIO_0_REGS, 19,0);
        
        McSPICycle(MCSPI_INST_HVS882_IDK, tx_data, 1, MCSPI_HVS882_CH_IDK);
        
        GPIOPinWrite(SOC_GPIO_1_REGS, 9,1);
        GPIOPinWrite(SOC_GPIO_0_REGS, 19,0);
        
        rx_data_hvs = (unsigned short)(tx_data[0] );
    }

    return rx_data_hvs;
}



unsigned short UTILsReadHVS2(void)
{
	return rx_data_hvs;
}

void UTILsICSSInit(void)
{
	UTILsICSSPRCMEnableStep1();
	DELAYMicroSeconds(200);
	UTILsICSSPRCMReset();
	DELAYMicroSeconds(200);

}

void UTILsPowerPWM(void)
{

	HWREG( SOC_PRCM_REGS + CM_PER_EPWMSS0_CLKCTRL) |= 0x2; 		// PWM0
    HWREG( SOC_PRCM_REGS + CM_PER_EPWMSS1_CLKCTRL) |= 0x2; 		// PWM1
	HWREG( SOC_PRCM_REGS + CM_PER_EPWMSS2_CLKCTRL) |= 0x2; 		// PWM2
	
	//enable the clocks
	HWREG( SOC_CONTROL_REGS + CONTROL_PWMSS_CTRL)  = 7; 		// all 3 clocks on

}

void UTILsResetPhys()
{
	if(AM335X_BOARD_TYPE_ICE_V2 == am335x_board_type)
	{
		GPIOPinWrite(SOC_GPIO_2_REGS, 5,0);
		DELAYMicroSeconds (300);
		GPIOPinWrite(SOC_GPIO_2_REGS, 5,1);
		DELAYMicroSeconds(300);
	}
	else
	{
		// connect TLK to SYSBOOT pin through FET: gpio0[12]
		GPIOPinWrite(SOC_GPIO_0_REGS, 12,0);
		GPIODirModeSet(SOC_GPIO_0_REGS, 12,0);

		// hold both ports in reset
		GPIOPinWrite(SOC_GPIO_2_REGS, 5,0);
		GPIOPinWrite(SOC_GPIO_1_REGS, 31,0);

		// enabling outputs
		GPIODirModeSet(SOC_GPIO_2_REGS, 5,0);
		GPIODirModeSet(SOC_GPIO_1_REGS, 31,0);

		// delay
		DELAYMicroSeconds(300);
		// enable port 0
		GPIOPinWrite(SOC_GPIO_2_REGS, 5,1);
		// need a delay, as port 0 will source port 1 with clock. ToDo: Check the length of the delay
		DELAYMicroSeconds(300);

		GPIOPinWrite(SOC_GPIO_1_REGS, 31,1);
	}
}

void UTILsTimer2Init(void)
{
	// make sure our Timer2 (BIOS 1ms) uses 32kHz ref clock
	// some boot loaders change that...
	*(unsigned int*)0x44E00508 = 2;			// select 32kHz
}

//GD void UTILsSetBoardType(unsigned char type)
//{
//	/*
//	 * This function should be replaced
//	 */
//	switch(type)
//	{
//	case AM335X_BOARD_TYPE_ICE:
//		am335x_board_type = AM335X_BOARD_TYPE_ICE;
//		break;
//	case AM335X_BOARD_TYPE_IDK:
//		am335x_board_type = AM335X_BOARD_TYPE_IDK;
//		break;
//	case AM335X_BOARD_TYPE_ICE_V2:
//		am335x_board_type = AM335X_BOARD_TYPE_ICE_V2;
//		break;
//	default:
//		am335x_board_type = AM335X_BOARD_TYPE_UNKNOWN;
//		break;
//	}
//GD}

unsigned char UTILsGetBoardType(void)
{
	return am335x_board_type;
}

int UTILsDetectBoardType()
{
//GD
//    unsigned char in_buff[2] = { 0 };
//	unsigned char out_buff[128];
//    unsigned char no_of_bytes = 0;
//
//    /*
//	 * i2c Slave address for EEPROM is 0x50
//	 *
//	*/
//
//	I2CInit(0);
//	I2CWrite(0,0x50,in_buff,2,&no_of_bytes);
//	if(I2CRead(0,0x50,out_buff,72,&no_of_bytes) == -1)
//		return -1;
//    if(EEPROM_MAGIC_NUM == (*(unsigned int*)out_buff))
//    {
//    	if(memcmp(&out_buff[4],ICE_V2_BOARD_NAME,9) == 0)
//        {
//            am335x_board_type = AM335X_BOARD_TYPE_ICE_V2;
//    		return AM335X_BOARD_TYPE_ICE_V2;
//        }
//    	else if(memcmp(&out_buff[4],ICE_BOARD_NAME,8) == 0)
//        {
//            am335x_board_type = AM335X_BOARD_TYPE_ICE;
//    		return AM335X_BOARD_TYPE_ICE;
//        }
//    	else if(memcmp(&out_buff[4],IDK_BASE_BOARD_NAME,8) == 0)
//        {
//            am335x_board_type = AM335X_BOARD_TYPE_IDK;
//    		return AM335X_BOARD_TYPE_IDK;
//        }
//
//    }
//GD    return AM335X_BOARD_TYPE_UNKNOWN;

	// NOTA: per semplificare si è eliminato l'autoriconoscimento della scheda.
	// Se si desidera usare la demo-board ICE basta scommentare i due assegnamenti seguenti
	//am335x_board_type = AM335X_BOARD_TYPE_ICE;
	//return AM335X_BOARD_TYPE_ICE;

	am335x_board_type = AM335X_BOARD_TYPE_IARD;
	return AM335X_BOARD_TYPE_IARD;
}


void UTILsInitCpswIcssPorts(unsigned char swicthType)
{
	GPIOPinWrite(SOC_GPIO_3_REGS, 4,1);
	if(ICSS_SWITCH == swicthType)
	{
		GPIOPinWrite(SOC_GPIO_3_REGS, 10,0);
		GPIOPinWrite(SOC_GPIO_0_REGS, 7,0);
	}
	else
	{
		GPIOPinWrite(SOC_GPIO_3_REGS, 10,1);
		GPIOPinWrite(SOC_GPIO_0_REGS, 7,1);
	}
	GPIOPinWrite(SOC_GPIO_0_REGS, 18,1);
	
	UTILsResetPhys();
}

/* -------------------------------------------------------------------------- */
/*                 Internal Function Definitions                              */
/* -------------------------------------------------------------------------- */

void UTILsICSSPRCMEnableStep1(void)
{
	HWREG( SOC_PRM_PER_REGS)      |= 0x2;
	HWREG( SOC_PRM_PER_REGS)      &= 0xFFFFFFFD;
	HWREG( SOC_PRCM_REGS + CM_PER_ICSS_CLKCTRL)      |= 0x2;
}

void UTILsICSSPRCMReset(void)
{
	HWREG( SOC_PRM_PER_REGS)   |= 0x2;
	HWREG( SOC_PRM_PER_REGS)   &= 0xFFFFFFFD;
}
