/**
 * \file main.c
 * \brief Contains main function and Application specific Tasks

 *
 * \copyright Copyright (c) 2012 Texas Instruments Incorporated ALL RIGHTS RESERVED
 *
*/

/* ========================================================================== */
/*                             Include Files                                  */
/* ========================================================================== */

#include <xdc/std.h>
#include <stdlib.h>
#include <xdc/runtime/Error.h>
#include <xdc/runtime/System.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>
#include <ti/sysbios/family/arm/a8/Mmu.h>

#include "stdio.h"
#include "string.h"
#include "soc_AM335x.h"
#include "evmAM335x.h"
#include "hw/hw_types.h"
#include "plat_uart.h"
#include "plat_cpsw.h"
#include "plat_utils.h"
#include "plat_i2c.h"
#include "plat_mux.h"
#include "plat_led.h"
#include "plat_gpio.h"
#include "osdrv_ndkdeviceconfig.h"
#include "osdrv_uart.h"
#include "osdrv_spiflash.h"
#include "osdrv_version.h"

#ifdef USE_CPSW_DRIVER
#include "cpsw_ethdriver.h"
#include "cpsw_impl.h"
#else
#include "icss_miimdio.h"
#include "icss_miimdio_regs.h"
#include "icss_nimu_eth.h"
#include "icss_pruInit.h"
#include "ethernetip_adapter_pru0_bin.h"
#include "ethernetip_adapter_pru1_bin.h"
#endif

#include "appl_cnfg.h"
#include "eip_main.h"
#include "icss_dlr.h"
#include "icss_eip_driver.h"


/* ========================================================================== */
/*                             Macros                                  */
/* ========================================================================== */
/**PRU0 Firmware Name*/
#define PRU0_FIRMWARE_NAME  PRU0_FIRMWARE
/**PRU1 Firmware Name*/
#define PRU1_FIRMWARE_NAME	PRU1_FIRMWARE

#ifdef USE_CPSW_DRIVER
/**Phy address of the CPSW port 0*/
	#define CPSW_PORT0_PHY_ADDR_IDK		30
/**Phy address of the CPSW port 1*/
	#define CPSW_PORT0_PHY_ADDR_ICE2	1
/**Phy address of the ICE2 CPSW port 1*/
	#define CPSW_PORT1_PHY_ADDR_ICE2	3
#else
/**Phy address of the ICSS port 0*/
	#define	ICSS_PORT0_PHY_ADDR          1
/**Phy address of the ICE2 ICSS port 0*/
	#define	ICSS_PORT0_PHY_ADDR_ICE2     1
/**Phy address of the ICSS port 1*/
	#define	ICSS_PORT1_PHY_ADDR          2
/**Phy address of the ICE2 ICSS port 1*/
	#define	ICSS_PORT1_PHY_ADDR_ICE2     3
#endif

/* ========================================================================== */
/*                            Global Variables                                */
/* ========================================================================== */

/**Uart instance used*/
unsigned int uartInstance =0;
/**Type of Board*/
unsigned char board_Type = 0;

/**Task handle for Led*/
Task_Handle led_task;
/**Task handle for EIP*/
Task_Handle main_task;

#ifdef DEBUG_LINK_STATUS
void DisplayLinkStatus(Uint32 linkStatus , Uint32 phyInstance );
#endif
void TaskFxn(UArg a0, UArg a1);
void LedFxn(UArg arg0, UArg arg1);
/**
 *  \name app_exit_handler
 *  \brief Exit handler for the application
 */
extern void app_exit_handler(int var);
#ifdef USE_CPSW_DRIVER
extern int CpswEmacInit (STKEVENT_Handle hEvent);
#else
extern int EmacInit (STKEVENT_Handle hEvent);
#endif
/* ========================================================================== */
/*                          Function Definitions                              */
/* ========================================================================== */


#ifndef USE_CPSW_DRIVER
/**
 *  \name TaskPruss
 *  \brief Task to initialize the PRU.
 *  \param a0
 *  \param a1
 *  \return none
 *
 */
void TaskPruss(UArg a0, UArg a1)
{
	Uint8 firmwareLoad_done = FALSE;

	while(GetNdkStatus(0)== NDK_STAT_PROGRESS || GetNdkStatus(0)==NDK_STAT_UNKNOWN)
	{
		Task_sleep(10);
	}

	ICSSSwitchInit();

	if( LoadPruFirmware((unsigned int *) PRU0_FIRMWARE_NAME,sizeof(PRU0_FIRMWARE_NAME),0) == 0)
	{
		if(LoadPruFirmware((unsigned int *) PRU1_FIRMWARE_NAME,sizeof(PRU1_FIRMWARE_NAME),1) == 0)
		{
			firmwareLoad_done = TRUE;
		}
	}

    if( firmwareLoad_done)
    {

    	StartSwitch();
		eip_driver_init();
		eip_driver_start();
    }
    else
    {
    	UARTPutString(uartInstance, "Error loading firmware\n");
    }
}

#endif

/**
 *  \name main
 *  \brief Main Function
 *  \param none
 *  \return none
 *
 */
void main()
{ 
	MAC_CONFIG config;
	MMUInit(applMmuEntries);
	board_Type = UTILsDetectBoardType();
    System_atexit(app_exit_handler);

    Task_Params taskParams;
    Task_Params_init(&taskParams);
    taskParams.priority = 1;
    taskParams.stackSize = 0x1400;
    main_task = Task_create (TaskFxn, &taskParams, NULL);

/*	Task_Params_init(&taskParams);
	taskParams.stackSize = 0x600;
	taskParams.priority = 5;
	led_task = Task_create (LedFxn, &taskParams, NULL);
*/
#ifdef USE_CPSW_DRIVER

#ifdef DEBUG_LINK_STATUS
	cpsw_register_link_change_notification(DisplayLinkStatus);
#endif

    if(AM335X_BOARD_TYPE_IDK == board_Type)
    {
    	PinMuxConfig(idkMux);
    	CPSWClkEnable();
    	LEDInit();

    	config.phyAddr[0] = CPSW_PORT0_PHY_ADDR_IDK;
    	config.numberPorts = 1;
    	config.macModeFlags = CPSW_CONFIG_MODEFLG_GIGABIT| CPSW_CONFIG_MODEFLG_FULLDUPLEX;
    	config.resvd = 1;
    	config.tlk110Flag =1;
    	SetMacConfiguration(&config);
    	uartInstance =3;
    	SpiFlashInit(1,0);
    }
    else if(AM335X_BOARD_TYPE_ICE_V2 == board_Type)
    {
    	GPIOInit();


    	/* Chip configuration MII/RMII selection */

    	PinMuxConfig(icev2Mux);
    	LEDInit();

    	UTILsInitCpswIcssPorts(CPSW_SWITCH);

	    CPSWClkEnable();


	    config.phyAddr[0] = CPSW_PORT0_PHY_ADDR_ICE2;
	    config.phyAddr[1] = CPSW_PORT1_PHY_ADDR_ICE2;
	    config.numberPorts = 2;
	    config.resvd = 1;
	    config.tlk110Flag =1;
	    config.macModeFlags = CPSW_CONFIG_MODEFLG_GIGABIT| CPSW_CONFIG_MODEFLG_FULLDUPLEX| CPSW_CONFIG_MODEFLG_IFCTLA;

	    SetMacConfiguration(&config);
//	    SpiFlashInit(0,0);
//EN
	    uartInstance = 3;
    }
    else if( AM335X_BOARD_TYPE_ICE == board_Type)
    {
    	BIOS_exit(0);
   }
    PortModeSelect_Ind();

    if(AddNetifEntryFn(&CpswEmacInit) == 0)
    		BIOS_exit(0);
    /*
     * Setting Task_sleep as the delay function for i2c enables i2c APIs to sleep
     * in between i2c operations ( instead of going to a tight loop ).
     * Here, while in CPSW mode on ICE V2, RMII clock is fed from a clock synthesizer
     * which is configured over i2c. This configuration fails if the delay function is not set.
     * Note that, from main, no i2c APIs shall be called after this call.
     */
    I2CSetDelayFn(Task_sleep);
#else

#ifdef DEBUG_LINK_STATUS
    EthdriverRegisterLinkChangeNotification(DisplayLinkStatus);
#endif
    ICSS_SWITCH_CONFIG switchConfig={QUEPRIO4,0,1,0}; //default params
    LEDInit();
	UTILsResetPhys();
    UTILsICSSInit();

    if( AM335X_BOARD_TYPE_ICE == board_Type)
    {
    	PinMuxConfig(iceMux);
    	PinMuxConfig(icev1Mux);
    	PRUSSPinMuxConfig(0x1); // PRUSS pinmuxing
    	uartInstance =5;
		config.phyAddr[0] = ICSS_PORT0_PHY_ADDR;
		config.phyAddr[1] = ICSS_PORT1_PHY_ADDR;
		config.numberPorts = 2;
		config.resvd = 0;
		config.tlk110Flag =1;
		switchConfig.enableIntrPacing = disablePacing;
		SetMacConfiguration(&config);
		SetIcssSwitchConfiguration(&switchConfig);
		SpiFlashInit(0,0);
    }
    else if(AM335X_BOARD_TYPE_IDK == board_Type)
    {
    	PinMuxConfig(idkMux);
       	PRUSSPinMuxConfig(0x1); // PRUSS pinmuxing
       	uartInstance =3;
        config.phyAddr[0] = ICSS_PORT0_PHY_ADDR;
		config.phyAddr[1] = ICSS_PORT1_PHY_ADDR;
		config.numberPorts = 2;
		config.resvd = 0;
		config.tlk110Flag =1;
		switchConfig.enableIntrPacing = disablePacing;
		SetMacConfiguration(&config);
		SetIcssSwitchConfiguration(&switchConfig);
		SpiFlashInit(1,0);
    }
    else if(AM335X_BOARD_TYPE_ICE_V2 == board_Type)
     {
    	PinMuxConfig(iceMux);
    	PinMuxConfig(icev2Mux);
        PRUSSPinMuxConfig(0x0); // PRUSS pinmuxing
        uartInstance = 3;
        switchConfig.halfDuplexEnable=1;
        switchConfig.enableIntrPacing = disablePacing;
        config.phyAddr[0] = ICSS_PORT0_PHY_ADDR_ICE2;
		config.phyAddr[1] = ICSS_PORT1_PHY_ADDR_ICE2;
		config.numberPorts = 2;
		config.resvd = 1;
		config.tlk110Flag =1;
		SetMacConfiguration(&config);
		SetIcssSwitchConfiguration(&switchConfig);
		SpiFlashInit(0,0);
     }

	Task_Params_init(&taskParams);
	taskParams.priority = 15;
	taskParams.instance->name = "SwitchTask";
	Task_create(TaskPruss, &taskParams, NULL);



    if(AM335X_BOARD_TYPE_ICE_V2 == board_Type)
    {
    	UTILsInitCpswIcssPorts(ICSS_SWITCH);
    }

	if(AddNetifEntryFn(&EmacInit) == 0)
		BIOS_exit(0);
#endif

	UartOpen(uartInstance, UartIsr);


    BIOS_start();
}




/**
 *  \name TaskFxn
 *  \brief Task which do EIP initialization
 *  \param a0
 *  \param a1
 *  \return none
 *
 */
void TaskFxn(UArg a0, UArg a1)
{
	char t_str[8];

	UARTPutString(uartInstance,"\n\rTI Industrial SDK Version - ");
	UARTPutString(uartInstance,IND_SDK_VERSION);

	UARTPutString(uartInstance,"\n\rDevice name \t: ");
	UARTPutString(uartInstance,UTILsGetDevName());

	UARTPutString(uartInstance,"\n\rChip Revision \t: ");
	UARTPutString(uartInstance,UTILsGetChipRevision());

	sprintf(t_str,"%d",UTILsGetArmClockRate());
	UARTPutString(uartInstance,"\n\rARM Clock rate \t: ");
	UARTPutString(uartInstance,t_str);

#ifdef USE_CPSW_DRIVER
	UARTPutString(uartInstance,"\n\rSYS/BIOS Ethernet/IP (CPSW) Sample application running on ");
#else
	UARTPutString(uartInstance,"\n\rSYS/BIOS Ethernet/IP (ICSS) Sample application running on ");
#endif

	if(AM335X_BOARD_TYPE_ICE  == board_Type)
	{
		UARTPutString(uartInstance,"ICE \n\r");
	}else if(AM335X_BOARD_TYPE_IDK  == board_Type)
	{
		UARTPutString(uartInstance,"IDK \n\r");
	}
	else if(AM335X_BOARD_TYPE_ICE_V2 == board_Type)
	{
		UARTPutString(uartInstance,"ICE V2 \n\r");
#ifdef USE_CPSW_DRIVER
		RMIIClock_setup();
#endif
	}
	//EIPMain();
}


#ifdef DEBUG_LINK_STATUS
/**
 *  \name DisplayLinkStatus
 *  \brief This function display the link status of phys
 *  \param linkStatus Status of the Link
 *  \param phyInstance Port instance
 *  \return none
 *
 */
void DisplayLinkStatus(Uint32 linkStatus , Uint32 phyInstance )
{
	printf("Link Status: %s on PHY %d\n",LinkStr[linkStatus],phyInstance);
}
#endif
