
#include <common.h>
#include <miiphy.h>
#include "atl_mii_mgmnt.h"

#define MIIM_CONTROL            0x00
#define MIIM_CONTROL_RESET	0x00009140
#define MIIM_CONTROL_INIT       0x00001140
#define MIIM_CONTROL_RESTART    0x00001340
#define MIIM_ANEN               0x00001000

#define MIIM_CR                 0x00
#define MIIM_CR_RST		0x00008000
#define MIIM_CR_INIT	        0x00001000

#define MIIM_STATUS		0x1
#define MIIM_STATUS_AN_DONE 	0x00000020
#define MIIM_STATUS_LINK	0x0004
#define PHY_BMSR_AUTN_ABLE	0x0008
#define PHY_BMSR_AUTN_COMP	0x0020

#define MIIM_PHYIR1		0x2
#define MIIM_PHYIR2		0x3

#define MIIM_ANAR		0x4
#define MIIM_ANAR_INIT		0x1e1

#define MIIM_TBI_ANLPBPA	0x5
#define MIIM_TBI_ANLPBPA_HALF	0x00000040
#define MIIM_TBI_ANLPBPA_FULL	0x00000020

#define MIIM_LPA_10HALF              0x0020  /* Can do 10mbps half-duplex   */
#define MIIM_LPA_10FULL              0x0040  /* Can do 10mbps full-duplex   */
#define MIIM_LPA_100HALF             0x0080  /* Can do 100mbps half-duplex  */
#define MIIM_LPA_100FULL             0x0100  /* Can do 100mbps full-duplex  */
#define MIIM_LPA_100BASE4            0x0200  /* Can do 100mbps 4k packets   */
#define MIIM_LPA_RESV                0x1c00  /* Unused...                   */
#define MIIM_LPA_RFAULT              0x2000  /* Link partner faulted        */
#define MIIM_LPA_LPACK               0x4000  /* Link partner acked us       */
#define MIIM_LPA_NPAGE               0x8000  /* Next page bit               */


#define MIIM_TBI_ANEX		0x6
#define MIIM_TBI_ANEX_NP	0x00000004
#define MIIM_TBI_ANEX_PRX	0x00000002

/*	SMI Address Register
 *
 *	Bit 	Name
 *	0-4		Register Address (REGAD)
 *	5-7		Reserved
 *	8-12	PHY Address (PHYAD)
 *	13-14	Reserved
 *	15		Read/Write (R/W)
 *
 *	WRITE-ONLY
 */
#define	KATANA_SMI_ADDRESS_REGISTER			0xFE300010
#define KATANA_SMI_READ_OPCODE 				0x8000
#define	KATANA_SMI_DEV_ADDR_SHIFT 			8


/* SMI Data Register
 * 16 bit READ / WRITE 
 */
#define KATANA_SMI_DATA_REGISTER			0xFE300012

/*	SMI Status Register
 *
 *	Bit		Name
 *	0		Ready State
 *	1		Idle state
 *	15-2	Reserved
 *
 *	READ-ONLY
 */
#define KATANA_SMI_STATUS_REGISTER			0xFE300014
#define KATANA_SMI_IDLE_STATE_BIT			0x0002
#define KATANA_SMI_READY_STATE_BIT			0x0001

/* SMI Control Register	
 *
 *	Bit		Name
 *	0		Reset State Machine
 *	1		Suppress Preamble
 *	2-15	Reserved
 *
 *	WRITE-ONLY
 */
#define KATANA_SMI_CONTROL_REGISTER			0xFE300016
#define KATANA_SMI_SUPPRESS_PREAMBLE_BIT	0x0002
#define KATANA_SMI_RESET_STATE_MACHINE_BIT	0x0001

#define ETH_FCC_CPLD_MDIO_IDLE_POLL_LIMIT 500
#define ETH_FCC_CPLD_MDIO_READY_POLL_LIMIT 100
#define ETH_FCC_CPLD_MDIO_READ_RETRY_LIMIT 3

#define ord16	unsigned short
#define ord32	unsigned int
#define utlDelayConvert 
#define DELAY_N_LOOPS( n ) udelay ( (n) )
#define DEBUG_PRNT printf

void atl_ar415_miiphy_init (void)
{
        ord16 dummy;
  
        miiphy_register("FCC1 ETHERNET", atl_ar415_miiphy_read,  atl_ar415_miiphy_write);
  
	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, MIIM_CONTROL, MIIM_CONTROL_RESET );
	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, MIIM_ANAR, MIIM_ANAR_INIT );
	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, MIIM_CONTROL, 0x1300);
	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, 0x17, 0x8000);
	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, 0x1c, 0x1044);
	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, 0x1d, 0x0005);
	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, 0x1e, 0x0004);
	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, 0x1f, 0x1121);
	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, 0x1c, 0x2044);
	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, 0x1d, 0x0004);
	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, 0x1e, 0x2111);
	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, 0x1f, 0x0040);
	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, 0x1c, 0x3044);
	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, 0x1d, 0x0100);
	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, 0x1e, 0x0000);
	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, 0x1f, 0x8000);
	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, 0x1c, 0x0044);
	
	atl_ar415_miiphy_read(NULL, CFG_PHY_ADDR, 0x1c, &dummy );


/*  set the port control register
*/	
//	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, PHY_MII_REG_CONTROL, PHY_MII_REG_C_RESET );
	
//	Parallel detect fault, Link change interrupt, autoneg complete
//	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, AC101L_REG_INT_CTRL_STAT, AC101L_REG_I_PDF_EN	|
//						AC101L_REG_I_LINK_EN |
//						AC101L_REG_I_ANCOMP_EN  ); // int ctrl
						
///*	setup the LEDs 
//*/
//// select page 1 
//	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, AC101L_REG_PHYMODE, AC101L_REG_PAGE1); // page 1
///* 	set global blink rate - 48ms, (48/16 = 3)
// */
// 	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, AC101L_REG_PG1_LED_BLINK, 0x0003); // blink
//
///* 	LED 0, Blink TX/RX, On Link
// */
//	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, AC101L_REG_PG1_LED0_SETTING1, AC101L_LED_EVENT_TXRX); // LED0-1
//	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, AC101L_REG_PG1_LED0_SETTING1, AC101L_LED_ON_EVENT_LINK); // LED0-2
//
////	select page 2
//	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, AC101L_REG_PHYMODE, AC101L_REG_PAGE2 );
//
///*  LED1, on with 100M && Link
// */
//	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR,  AC101L_REG_PG2_LED1_SETTING1, 0x0000 );
//	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR,  AC101L_REG_PG2_LED1_SETTING2, AC101L_LED_ON_EVENT_100|AC101L_LED_ON_EVENT_LINK );
//
///* 	LED2, Blink collision, on full duplex
// */
//	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR,  AC101L_REG_PG2_LED2_SETTING1, AC101L_LED_EVENT_COL );
////	select page 3 
//	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR,  AC101L_REG_PHYMODE, AC101L_REG_PAGE3 );
//	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, AC101L_REG_PG3_LED2_SETTING2, AC101L_LED_ON_EVENT_DUP|AC101L_LED_ON_EVENT_LINK );
//
///* 	LED3, Does nothing just set everyting to 0
// */
//	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, AC101L_REG_PG3_LED3_SETTING1, 0x0000 );	
//	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, AC101L_REG_PG3_LED3_SETTING2, 0x0000 );	
//
//	/* select page 0 */
//	atl_ar415_miiphy_write(NULL, CFG_PHY_ADDR, AC101L_REG_PHYMODE, AC101L_REG_PAGE0 );

}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *
 * ethFCCCpld415WriteMII()
 *
 * Performs a write using the MII management controller.
 * This routine is specific to the AR415 hardware. 
 *
 * Parameters:
 *	 ETHInstance * instPt - ethernet instance
 *	 ord8 regId - register number
 *	 ord16 device - MII device address
 *	 ord16 value - value to write
 *
 * Constraints:
 *
 * Side Effects:
 * 
 * Created: 
 * 	9/1/2006
 * 
 * Author: 
 * 	Chris Packham
 * 
 * Returns: 
 * 	ord32  - True if write was sucessfull
 *
 */
int atl_ar415_miiphy_write (char *devname, unsigned char device,
		unsigned char regId, unsigned short value)
{
	ord16			  address;
 	ord16			  twoMicroSec;
	ord32			  count;
	
	volatile ord16			* dataPt ;
	volatile ord16			* addrPt ;
	volatile ord16			* statusPt ;
	volatile ord16			* ctrlPt ;

	dataPt = 	( volatile ord16 *) KATANA_SMI_DATA_REGISTER ;
	addrPt = 	( volatile ord16 *) KATANA_SMI_ADDRESS_REGISTER ;
	statusPt = 	( volatile ord16 *) KATANA_SMI_STATUS_REGISTER ;
	ctrlPt = 	( volatile ord16 *) KATANA_SMI_CONTROL_REGISTER ;	
		
	twoMicroSec = utlDelayConvert( ( ord16 )2 );
		
/*	Calculate the PHY Address. The method for calculating the address depends 
 *	on the address type. 
 *
 *	The format of the Address register is: 
 *	Bits	Name 
 *	15		Read / Write bit
 *	14-13	Reserved
 *	12-8	PHY Address (PHYAD)
 *	7-5		Reserved
 *	4-0		Register Address (REGAD)
 */   

	address = ( ord16 )( ( device << KATANA_SMI_DEV_ADDR_SHIFT ) + ( ord16 )regId );	
	
/*	Use the CPLD to write through MDIO. First check that the Idle State bit in
 *	the SMI Status register is set. This indicates that the State Machine is 
 *	able to begin a new MDIO transaction.  
 */	
	for ( count = 0; ( *statusPt & KATANA_SMI_IDLE_STATE_BIT ) == 0  && count < ETH_FCC_CPLD_MDIO_IDLE_POLL_LIMIT; count++ )
	{
		DELAY_N_LOOPS( twoMicroSec ); 
	}

	if (count >= ETH_FCC_CPLD_MDIO_IDLE_POLL_LIMIT )
	{
/*		If the Idle State bit is not set, then set the Reset State Machine bit 
 *		in the SMI Control Register to return the State Machine to the Idle 
 *		state. The reset should be instantaneous, so don't need to then poll the 
 *		Idle State bit to ensure it is set.  
 */
		DEBUG_PRNT( "Write RESET %x\r\n", *statusPt, 4);
					
		DELAY_N_LOOPS(twoMicroSec);
//		OP_ACC_BIT_ON_WO( phyPt->miiMgmnt.miiInfoV1.miiReset ); 
		*ctrlPt = KATANA_SMI_RESET_STATE_MACHINE_BIT ;

/*		Even though the SMI reset should be instantaneous, wait 2u anyway to 
 *		be sure.
 */		
		DELAY_N_LOOPS(twoMicroSec);
	}
	else
	{
//		DEBUG_PRNT( "Write OK %u %x\r\n", count, *statusPt, 4);
		DELAY_N_LOOPS(twoMicroSec);
	}

   
/*	Write the value to the Data register.
 */	
	*dataPt = value; 	
	DELAY_N_LOOPS( twoMicroSec );

/*	Write the address to the Address register. The opcode for a MDIO write is 
 *	zero (Read/Write bit is cleared). For both MDIO Reads and Writes, writing to 
 *	the Address register initiates the transaction. 
 */
 	*addrPt = address;

//	DEBUG_PRNT( " mii write %s: %x, DevAddr: %x, Data: %x\r\n", 
//					devname == NULL ? "NULL" : devname,
//					regId , device, value  );
	
		
} /* ethFCCCpld415WriteMII */


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *
 * ethFCCCpld415ReadMII()
 *
 * Performs a read using the MII management controller.
 * This routine is specific to the AR415 hardware.
 *
 * Parameters:
 *	 ETHInstance * instPt - ethernet instance
 *	 ord8 regId - register number
 *	 ord16 device - MII device address
 *	 ord16 *dataPt - variable to store result of read
 *
 * Constraints:
 *
 * Side Effects:
 * 
 * Created: 
 * 	9/1/2006
 * 
 * Author: 
 * 	Chris Packham
 * 
 * Returns: 
 * 	ord32  - TRUE if read was sucessfull
 *
 */
int atl_ar415_miiphy_read (char *devname, unsigned char device,
		unsigned char regId, unsigned short *value)
{
 	ord16			  twoMicroSec;
	ord16			  address;
	ord32			  count;
	ord32			  counter;
	ord32			  retries;

	volatile ord16			* dataPt ;
	volatile ord16			* addrPt ;
	volatile ord16			* statusPt ;
	volatile ord16			* ctrlPt ;

	dataPt = 	(volatile ord16 *) KATANA_SMI_DATA_REGISTER ;
	addrPt = 	(volatile ord16 *) KATANA_SMI_ADDRESS_REGISTER ;
	statusPt = 	(volatile ord16 *) KATANA_SMI_STATUS_REGISTER ;
	ctrlPt = 	(volatile ord16 *) KATANA_SMI_CONTROL_REGISTER ;	


	twoMicroSec = utlDelayConvert( ( ord16 )2 );
	
/*	Calculate the address. The method for calculating the address depends 
 *	on the address type. 
 *
 *	The format of the SMI Address register is: 
 *	Bits	Name 
 *	15		Read / Write bit
 *	14-13	Reserved
 *	12-8	Device Address
 *	7-5		Reserved
 *	4-0		Register Address
 *
 */   
	address = ( ord16 )( ( device << KATANA_SMI_DEV_ADDR_SHIFT ) + ( ord16 )regId );	

	for ( count = 0; ( *statusPt & KATANA_SMI_IDLE_STATE_BIT ) == 0  
		&& count < ETH_FCC_CPLD_MDIO_IDLE_POLL_LIMIT; count++ )
	{
		DELAY_N_LOOPS(twoMicroSec); 
	}

	if (count >= ETH_FCC_CPLD_MDIO_IDLE_POLL_LIMIT )
	{
/*		If the Idle State bit is not set, then set the Reset State Machine bit 
 *		in the SMI Control Register to return the State Machine to the Idle 
 *		state. The reset should be instantaneous, so don't need to then poll the 
 *		Idle State bit to ensure it is set.  
 */
 		DELAY_N_LOOPS( twoMicroSec);
//		OP_ACC_BIT_ON_WO( phyPt->miiMgmnt.miiInfoV1.miiReset ); 
		*ctrlPt = KATANA_SMI_RESET_STATE_MACHINE_BIT ;

/*		Even though the SMI reset should be instantaneous, wait 2u anyway to 
 *		be sure.
 */				
		DELAY_N_LOOPS( twoMicroSec);
		DEBUG_PRNT( "Read RESET\r\n" );
	}	

   	 		
	counter = 0;
	retries = 0;
	
/*	Perform the Read. This transaction will be tried up to CPLD_MDIO_RETRY_LIMIT 
 *  times. 
 */		
	while( 1 )
	{		
/*		Write the address to the SMI Address register. The opcode for a MDIO 
 *		read is one (Read/Write bit is set). For both MDIO Reads and Writes, 
 *		writing to the Address register initiates the transaction.
 */
 		*addrPt = address | KATANA_SMI_READ_OPCODE;
		DELAY_N_LOOPS( twoMicroSec );


/*		Poll the Ready State bit in the Status register. When this bit is 
 *		set, the Data register can be read. Limit the number of polls to avoid 
 *		an infinite wait.
 */
		while( counter < ETH_FCC_CPLD_MDIO_READY_POLL_LIMIT )	
		{
			if ( ( *statusPt & KATANA_SMI_READY_STATE_BIT ) != 0  )
			{
				break;
			}
/*			Polling interval is about 2u. 
 */		
			DELAY_N_LOOPS( twoMicroSec );
			counter++;
		}								
		
/*		Check if the Ready state bit was found to be set during the polling 
 *		interval. 
 */		
		if ( counter >= ETH_FCC_CPLD_MDIO_READY_POLL_LIMIT )
		{
/*			If the Ready State bit was not set after a polling cycle has been 
 *			completed, retry the transaction if the retry limit has not been 
 *			reached. 
 */ 		
			retries++;		
			if( retries > ETH_FCC_CPLD_MDIO_READ_RETRY_LIMIT )
			{			
				DEBUG_PRNT( "Ready State bit not set, retry limit exceeded\r\n" );
				return( 1 );
			}
			else
			{				
/*				To retry the transaction, first return the State Machine to the 
 *				Idle state by setting the Reset State Machine bit in the Control 
 *				register.
 */				
 				DELAY_N_LOOPS( twoMicroSec );						
		//		OP_ACC_BIT_ON_WO( phyPt->miiMgmnt.miiInfoV1.miiReset ); 
				*ctrlPt = KATANA_SMI_RESET_STATE_MACHINE_BIT ;
				
/*				Even though the SMI reset should be instantaneous, wait 2u anyway to 
 *				be sure.
 */							
				DELAY_N_LOOPS( twoMicroSec );			
				
/*				Reset the polling counter. 
 */				
				counter = 0;
									
			  	DEBUG_PRNT( "Ready State bit is not set, attempt=%u\r\n", retries );
			}
		}
		else
		{
/*			The Ready state bit must be set, so move on to reading the Data 
 *			register. 
 */			
 			DELAY_N_LOOPS( twoMicroSec );
			break;
		}
	}
	
/*	Read the Data register. 
 */
	*value = *dataPt;	
	DELAY_N_LOOPS( twoMicroSec );
				
	return ( 0 );
	
} /* ethFCCCpld415ReadMII */
