/*
 * ethernet.c
 *
 ******************************************************************************/
#include <ti/sysbios/BIOS.h>
#include <xdc/std.h>
#include "drivers.h"
#include "cpsw_ethdriver.h"
#include "cpsw_impl.h"

#include "hw_types.h"
#include "hw_mdio.h"
#include "mdio.h"
#include "soc_AM335x.h"

#include "./os/osif.h"

/* ========================================================================== */
/*                             Macros                                         */
/* ========================================================================== */
#define CPSW_PORT0_PHY_ADDR_ICE2	1
#define CPSW_PORT1_PHY_ADDR_ICE2	3
#define MDIO_FREQ_IN					125 * 10^6
/* Frequenza del clock in uscita dall'MDIO verso il fisico  (max 25MHz per il TLK110)*/
#define MDIO_FREQ_OUT					  1 * 10^6

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


static int nimu_device_index = 0U;
MAC_CONFIG mac_configuration;

NIMU_DEVICE_TABLE_ENTRY NIMUDeviceTable[MAX_TABLE_ENTRIES];
extern int 	CpswEmacInit 				( STKEVENT_Handle hEvent );
extern void CPSWClkEnable				( void );
void 		ethernet_init_tlkt			( void );
void 		ethernet_MDIOInit			( void );
void 		ethernet_delay_microseconds	( unsigned int duration );

extern void GPIOInit					( void );
extern void MDIOPhyAutoMDIXEnable		( unsigned int baseAddr, unsigned int phyAddr );
extern void PortMIIModeSelect			( void );

extern OSENVCFG _oscfg;

/* -------------------------------------------------------------------------- */
/* cpsw_MDIO_FindingState
** The main function
*/
int 	ethernet_init	(void)
{

	GPIOInit();				/* GPIOClockEnable + GPIOEnablePins */
    CPSWClkEnable();		/* Enables CPSW clocks */

	ethernet_init_tlkt();	/* ciclo di reset iniziale del tlk110 */

	ethernet_MDIOInit();
	MDIOPhyAutoMDIXEnable(SOC_CPSW_MDIO_REGS, 30);

	PortMIIModeSelect();	/* Chip configuration MII/RMII selection (in questo caso è MII) */

    mac_configuration.phyAddr[0] = 30;
    mac_configuration.numberPorts = 1;
    mac_configuration.resvd = 1;
    mac_configuration.tlk110Flag =1;
    mac_configuration.macModeFlags = CPSW_CONFIG_MODEFLG_FULLDUPLEX| CPSW_CONFIG_MODEFLG_IFCTLA;

    nimu_device_index = 0U;
    NIMUDeviceTable[nimu_device_index++].init =  &CpswEmacInit ;
    NIMUDeviceTable[nimu_device_index].init =  NULL ;

//    _oscfg.DbgPrintLevel = DBG_NONE;

    return ( TRUE );

}

void ethernet_MDIOInit(void)
{
   unsigned int clkDiv;
   unsigned int baseAddr;		//Base Address of the MDIO Module Registers
   unsigned int mdioInputFreq;	//The clock input to the MDIO module
   unsigned int mdioOutputFreq;	//The clock output required on the MDIO bus

   mdioInputFreq = MDIO_FREQ_IN;
   mdioOutputFreq = MDIO_FREQ_OUT;
   clkDiv = (mdioInputFreq/mdioOutputFreq) - 1;
   baseAddr = SOC_CPSW_MDIO_REGS;

   HWREG(baseAddr + MDIO_CONTROL) = ((clkDiv & MDIO_CONTROL_CLKDIV)
                                     | MDIO_CONTROL_ENABLE
                                     | MDIO_CONTROL_PREAMBLE
                                     | MDIO_CONTROL_FAULTENB
                                     );

   while (HWREG(baseAddr + MDIO_ALIVE)==0);

}

/* -------------------------------------------------------------------------- */
/*
** Esegue la sequenza di reset per il TLK110 dell'ethernet
*/
void ethernet_init_tlkt(void)
{
	// Enable Out Reset Ethernet
	*((unsigned int*) 0x44E07134) &= 0xDFFFFFFF; 	// enable output bit gpio0[29]

	/* Reset alto */
	*((unsigned int*) 0x44E07194)  = 0x20000000; 	// set gpio0[29]-> Ethernet
	ethernet_delay_microseconds(10);

	/* Reset basso */
	*((unsigned int*) 0x44E07190)  = 0x20000000; 	// clear gpio0[29]
	ethernet_delay_microseconds(100);

	/* Reset alto */
	*((unsigned int*) 0x44E07194)  = 0x20000000; 	// set gpio0[29]
}

/* -------------------------------------------------------------------------- */
/*
** routine di delay minimale ma funzionale
*/
void ethernet_delay_microseconds(unsigned int duration)
{
    volatile unsigned int loopCntr;
    volatile unsigned int delay;

    delay = duration * 72;	//Mediamente 1ciclo=14nS

    for ( loopCntr = 0 ; loopCntr < delay ; loopCntr++ ){ };
}
