/**
 * \file   plat_cpsw.c
 *
 * \brief  
 *
 * 
*/

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

/* ========================================================================== */
/*                             Include Files                                  */
/* ========================================================================== */
#include "plat_cpsw.h"
#include "plat_mux.h"
#include "plat_i2c.h"
/* ========================================================================== */
/*                           Macros & Typedefs                                */
/* ========================================================================== */
#define RMIICLOCK_I2C_INST_NUM  0
#define RMIICLOCK_I2C_ADDR      0x65

#define ID_REG      0
#define XCSEL		0x05

/*PLL1 Configuration Register*/
#define MUX_REG		0x14
#define PDIV2_REG	0x16
#define PDIV3_REG	0x17
/* ========================================================================== */
/*                         Structures and Enums                               */
/* ========================================================================== */

/* ========================================================================== */
/*                 Internal Function Declarations                             */
/* ========================================================================== */ 
/**
 * \brief   
 *
 * \param   
 *
 *
 * \return  
 *
 **/ 
/* ========================================================================== */
/*                            Global Variables                                */
/* ========================================================================== */
extern unsigned char am335x_board_type;
/* ========================================================================== */
/*                          Function Definitions                              */
/* ========================================================================== */




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

void CPSWPinMuxSetup_Ind(void)
{
	if(AM335X_BOARD_TYPE_IDK == am335x_board_type)
	{
		/*for use in MII mode. */
		HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_COL) =
				 CONTROL_CONF_MII1_COL_CONF_MII1_COL_RXACTIVE
				 | CPSW_GMII_SEL_MODE;
		HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_CRS) =
				 CONTROL_CONF_MII1_CRS_CONF_MII1_CRS_RXACTIVE
				 | CPSW_GMII_SEL_MODE;
		HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_RXERR) =
				 CONTROL_CONF_MII1_RXERR_CONF_MII1_RXERR_RXACTIVE
				 | CPSW_GMII_SEL_MODE;
		HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_TXEN) =
				  CPSW_GMII_SEL_MODE;
		HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_RXDV) =
				  CONTROL_CONF_MII1_RXDV_CONF_MII1_RXDV_RXACTIVE
				  | CPSW_GMII_SEL_MODE;
		HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_TXD3) =
				  CPSW_GMII_SEL_MODE;
		HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_TXD2) =
				  CPSW_GMII_SEL_MODE;
		HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_TXD1) =
				  CPSW_GMII_SEL_MODE;
		HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_TXD0) =
				  CPSW_GMII_SEL_MODE;
		HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_TXCLK) =
				  CONTROL_CONF_MII1_TXCLK_CONF_MII1_TXCLK_RXACTIVE    //Modification from
				  | CPSW_GMII_SEL_MODE;
		HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_RXCLK) =
				  CONTROL_CONF_MII1_RXCLK_CONF_MII1_RXCLK_RXACTIVE
				  | CPSW_GMII_SEL_MODE;
		HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_RXD3) =
				  CONTROL_CONF_MII1_RXD3_CONF_MII1_RXD3_RXACTIVE
				  | CPSW_GMII_SEL_MODE;
		HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_RXD2) =
				  CONTROL_CONF_MII1_RXD2_CONF_MII1_RXD2_RXACTIVE
				  | CPSW_GMII_SEL_MODE;
		HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_RXD1) =
				  CONTROL_CONF_MII1_RXD1_CONF_MII1_RXD1_RXACTIVE
				  | CPSW_GMII_SEL_MODE;
		HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_RXD0) =
				  CONTROL_CONF_MII1_RXD0_CONF_MII1_RXD0_RXACTIVE
				  | CPSW_GMII_SEL_MODE;
		HWREG(SOC_CONTROL_REGS + CONTROL_CONF_RMII1_REFCLK) =
				  CONTROL_CONF_RMII1_REFCLK_CONF_RMII1_REFCLK_RXACTIVE;
		HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MDIO_DATA) =
				  CONTROL_CONF_MDIO_DATA_CONF_MDIO_DATA_RXACTIVE
				  | CONTROL_CONF_MDIO_DATA_CONF_MDIO_DATA_PUTYPESEL
				  | CPSW_MDIO_SEL_MODE;
		HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MDIO_CLK) =
				  CONTROL_CONF_MDIO_CLK_CONF_MDIO_CLK_PUTYPESEL
			  | CPSW_MDIO_SEL_MODE;	
	}
	else if(AM335X_BOARD_TYPE_ICE_V2 == am335x_board_type)
	{
		/* MDIO Pin mux setting */
		HWREG( SOC_CONTROL_REGS + CONTROL_CONF_MDIO_DATA) = ( PINMUXMODE_1
				| (0x1 << CONTROL_CONF_MDIO_DATA_CONF_MDIO_DATA_PUTYPESEL_SHIFT)
				| (0x1 << CONTROL_CONF_MDIO_DATA_CONF_MDIO_DATA_RXACTIVE_SHIFT));

		HWREG( SOC_CONTROL_REGS + CONTROL_CONF_MDIO_CLK) = ( PINMUXMODE_1
				| (0x1 << CONTROL_CONF_MDIO_CLK_CONF_MDIO_CLK_PUTYPESEL_SHIFT));	
	    /*Pin Mux for RMII1  */
	    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_TXD0) = //RMII1_TXD0
	        PINMUXMODE_2;

	    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_TXD1) = //RMII1_TXD1
	    	PINMUXMODE_2;

	    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_TXEN) = //RMII1_TXEN
	    	PINMUXMODE_2;

	    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_CRS) = //RMII1_CRS
	        PINMUXMODE_2 | AM335X_PIN_INPUT;

	    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_RXD0) = //RMII1_RXD0
	        PINMUXMODE_2 | AM335X_PIN_INPUT;

	    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_RXD1) = //RMII1_RXD1
	        PINMUXMODE_2 | AM335X_PIN_INPUT;

	    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_RXERR) = //RMII1_RXERR
	   	    PINMUXMODE_2 | AM335X_PIN_INPUT;

	    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_RMII1_REFCLK) = //AM335X_REFCLK_RMII1
	   	    (PINMUXMODE_1
	    	| (0x1 << CONTROL_CONF_RMII1_REFCLK_CONF_RMII1_REFCLK_PUTYPESEL_SHIFT)
	    	| (0x1 << CONTROL_CONF_RMII1_REFCLK_CONF_RMII1_REFCLK_RXACTIVE_SHIFT));

	    /* Pin Mux for RMII2 */
	    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_GPMC_A(0)) =  //RMII2_TXEN
	    	PINMUXMODE_4;

	    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_GPMC_A(4)) =  //RMII2_TXD1
	        PINMUXMODE_4;

	    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_GPMC_A(5)) =	 //RMII2_TXD0
	        PINMUXMODE_4;

	    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_GPMC_A(10)) = //RMII2_RXD1
	    	PINMUXMODE_4 | AM335X_PIN_INPUT;

	    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_GPMC_A(11)) = //RMII2_RXD0
	    	PINMUXMODE_4 | AM335X_PIN_INPUT;

	    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_GPMC_WAIT0) = //RMII2_CRS_DV
	    	PINMUXMODE_4 | AM335X_PIN_INPUT;

	    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_GPMC_WPN)   =  //RMII2_RXERR
	        PINMUXMODE_4 | AM335X_PIN_INPUT;

	    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_COL) = //AM335X_REFCLK_RMII2
	   	    (PINMUXMODE_2
	    	| (0x1 << CONTROL_CONF_MII1_COL_CONF_MII1_COL_PUTYPESEL_SHIFT)
	    	| (0x1 << CONTROL_CONF_MII1_COL_CONF_MII1_COL_RXACTIVE_SHIFT));


		/*GPIO2_5 for Ethernet 0 & 1 Reset */
	 	HWREG(SOC_CONTROL_REGS + CONTROL_CONF_GPMC_BE0N_CLE) = PINMUXMODE_8;

	 	/* GPIO3_21 for CTL_SYS_BOOT of U37 and U38 to isolate the SYSBOOT Resistors from the PHY pins*/
	 	HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MCASP0_AHCLKX) = PINMUXMODE_8;

	 	/* GPIO3_10 for MUX control configuration 0- PRU-MII1 , 1- RMII2 */
	    HWREG(SOC_CONTROL_REGS + CONTROL_CONF_MII1_RXCLK) = PINMUXMODE_8;


	    /*Enable PR1_MII0_RXLINK->B_PRUETH0_LINKLED, PRUETH0_RXERR_COL_PROC->PRUETH0_RXERR_COL11 */
	   	HWREG(SOC_CONTROL_REGS + CONTROL_CONF_ECAP0_IN_PWM0_OUT) =
	   			PINMUXMODE_8 |
	   			CONTROL_CONF_ECAP0_IN_PWM0_OUT_CONF_ECAP0_IN_PWM0_OUT_PUDEN &
	   			~CONTROL_CONF_ECAP0_IN_PWM0_OUT_CONF_ECAP0_IN_PWM0_OUT_PUTYPESEL &
	   			~CONTROL_CONF_ECAP0_IN_PWM0_OUT_CONF_ECAP0_IN_PWM0_OUT_RXACTIVE &
	   			~CONTROL_CONF_ECAP0_IN_PWM0_OUT_CONF_ECAP0_IN_PWM0_OUT_SLEWCTRL;

	   	/* DDR_VTT_EN set high */
	   	HWREG(SOC_CONTROL_REGS + CONTROL_CONF_USB_DRVVBUS(0)) =
	   			PINMUXMODE_8 |
	   			CONTROL_CONF_ECAP0_IN_PWM0_OUT_CONF_ECAP0_IN_PWM0_OUT_PUDEN &
	   			~CONTROL_CONF_ECAP0_IN_PWM0_OUT_CONF_ECAP0_IN_PWM0_OUT_PUTYPESEL &
	   			~CONTROL_CONF_ECAP0_IN_PWM0_OUT_CONF_ECAP0_IN_PWM0_OUT_RXACTIVE &
	   			~CONTROL_CONF_ECAP0_IN_PWM0_OUT_CONF_ECAP0_IN_PWM0_OUT_SLEWCTRL;
		
	}
	else if(AM335X_BOARD_TYPE_IARD == am335x_board_type)	//GD
	{
		// In caso di IARD il pin mux è stato già configurato nella driver_init() in drivers.c
	}
}

void PortMIIModeSelect(void)
{
    /* Select MII, Internal Delay mode */
    HWREG(SOC_CONTROL_REGS + CONTROL_GMII_SEL) = 0x00;
}


void PortRMIIModeSelect(void)
{
    /* Select RMII, Internal Delay mode */
    HWREG(SOC_CONTROL_REGS + CONTROL_GMII_SEL) = 0xC5;
}

 void PortModeSelect_Ind(void)
 {
    if(AM335X_BOARD_TYPE_IDK  == am335x_board_type)
    {
		PortMIIModeSelect();
	}
	else if(AM335X_BOARD_TYPE_ICE_V2 == am335x_board_type)
    {
		PortRMIIModeSelect();
    }	
    else if(AM335X_BOARD_TYPE_IARD == am335x_board_type)	//GD
    {
		PortMIIModeSelect();
    }
 }
 
int RMIIClockRead(unsigned char registerAddr, unsigned char *readBuf)
{
	int retVal = SUCCESS;
	unsigned char dataWritten  = 0;

	registerAddr |= 0x80;

	/* Send the Command Byte as Register 9(Input Port Register) read address 0x00 to the Rotary Switch via I2C write call */
    retVal = I2CWrite(RMIICLOCK_I2C_INST_NUM, RMIICLOCK_I2C_ADDR,&registerAddr,1,&dataWritten);

    if (FAIL == retVal)
    {
        return retVal;
    }

    /* Wait for Clock Synthesizer to process */
    I2CDelay(100);

    /* Read data */
    retVal = I2CRead(RMIICLOCK_I2C_INST_NUM, RMIICLOCK_I2C_ADDR, readBuf, 1, &dataWritten);
    if (FAIL == retVal )
    {
        return retVal;
    }


    return retVal;
}

int RMIIClockWrite(unsigned char registerAddr, unsigned char writeData)
{
    int retVal = SUCCESS;
	unsigned char cmd[2];
	unsigned char dataWritten = 0;

	cmd[0] = registerAddr|0x80;  // Register address
	cmd[1] = writeData;     // Register Data

	/* Send register address and data */
	retVal = I2CWrite( RMIICLOCK_I2C_INST_NUM, RMIICLOCK_I2C_ADDR, cmd, 2, &dataWritten);

	if (FAIL == retVal)
	{
		return retVal;
	}

	/* Wait for Clock Synthesizer to process */
	I2CDelay(100);

	return retVal;
}

int RMIIClock_setup()
{

    int retVal = FAIL;
	unsigned char regValue=0;
	/* Initialize the I2C Bus */
    /*
     * It is obsereved that Clock Synthesizer doesn't behave as expected when i2c module is 
     * already configured. To workaround this issue, here I2CReInit is called ( which intialize i2c module forcefully).
	//retVal = I2CReInit(0);
     */
    
    retVal = I2CInit(0);
	if (FAIL == retVal)
	{
		return retVal;
	}

	retVal = RMIIClockRead(ID_REG,&regValue);
	if (FAIL == retVal)
	{
			return retVal;
	}

	if((regValue&0x81)!=0x81)
	{
		return FAIL;
	}

	/* CDCE913 Clock Synthesizer configuration for RMII Clock = 50 MHz
	 * fout = fin/Pdiv x N/M
	 * fout = 50 MHz
	 * fin  = 25 MHz
	 * Pdiv = 2
	 * N    = 4
	 * M    = 1
	 * Calculated using the TI ClockPro Programming Software
	 * http://www.ti.com/tool/clockpro
	 */
	retVal = RMIIClockWrite(XCSEL,0x90);  //Crystal load Capacitor Selection - 18pF: 0x12h(bits 7:3)
	if (FAIL == retVal)
	{
		return retVal;
	}

	retVal = RMIIClockWrite(MUX_REG,0x6D); //PLL1 Multiplexer b7:0(PLL1)
	if (FAIL == retVal)
	{
		return retVal;
	}

	retVal = RMIIClockWrite(PDIV2_REG,0x02); //b7-0(PLL1 SSC down selection by default), b6:0-0x02h(7-bit Y2-Output-Divider Pdiv2)
	if (FAIL == retVal)
	{
		return retVal;
	}

	retVal = RMIIClockWrite(PDIV3_REG,0x02);//b6:0-0x02h(7-bit Y3-Output-Divider Pdiv3)
	if (FAIL == retVal)
	{
		return retVal;
	}
	return SUCCESS;
}

