/********************
* Original work (C) COPYRIGHT 2006 STMicroelectronics **************************
* Modifications (C) CopyRight 2006 Richard barry
* File Name          : 91x_enet.c
* Author             : MCD Application Team
* Date First Issued  : May 2006
* Description        : ENET library functions
********************************************************************************
* History:
* May 2006: v1.0
********************************************************************************
* THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*******************************************************************************/


/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "91x_lib.h"
#include "string.h"  //include when using memcpy function

/* Include of other module interface headers ---------------------------------*/
/* Local includes ------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#ifndef NULL
#define NULL    (0)
#endif
/* Function return values */
#define ENET_OK  (1)
#define ENET_NOK (0)

/* PHY interface constants. */
#define STE100P_STATUS_REG				0x01
#define STE100P_CONTROL_REG				0x00
#define STE100P_LINK_ABILITY			0x05
#define STE100P_STATUS_LINKED			0x0004
#define STE100P_AUTO_NEGOTIATE_ABILITY	0x1000
#define STE100P_AUTO_NEGOTIATE_COMPLETE 0x20
#define STE100P_10HALF              	0x0020
#define STE100P_10FULL              	0x0040
#define STE100P_100HALF             	0x0080
#define STE100P_100FULL             	0x0100
#define STE100P_CTRL_FULL           	0x0100


/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
#define ENET_NUM_RX_BUFFERS 8

static ENET_DMADSCRBase  dmaTxDscrBase, dmaRxDscrBase[ ENET_NUM_RX_BUFFERS ];
static u8 RxBuff[ ENET_NUM_RX_BUFFERS ][ENET_BUFFER_SIZE];
u8 TxBuff[ENET_BUFFER_SIZE];

/* Interface functions -------------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/*******************************************************************************
* Function Name  : ENET_SetMACConfig(ENET_MACConfig * MAC_Config)
* Description    : MAC Control Register Configuration
* Input          : MAC_Config structure
* Output         : None
* Return         : None
*******************************************************************************/
void ENET_MACControlConfig(ENET_MACConfig *MAC_Config)
{
  /* ReceiveALL bit */
  if (MAC_Config->ReceiveALL==ENABLE) ENET_MAC->MCR |= MAC_MCR_RA;
  else ENET_MAC->MCR &=~MAC_MCR_RA;

  /* MIIPrescaler */
  ENET_MAC->MCR &=~(0x3<<24);
  if ((MAC_Config->MIIPrescaler) == MIIPrescaler_2)
  ENET_MAC->MCR |=0x1<<24;

  /* Loopback mode */
  if (MAC_Config->LoopbackMode==ENABLE)
  {
    ENET_MAC->MCR &=~MAC_MCR_LM;
    ENET_MAC->MCR |=0x1<<21;
    ENET_MAC->MCR &=~MAC_MCR_DRO;  /*enable frame reception during transmission*/
  }

  /* Address filtering mode */
  ENET_MAC->MCR &=~MAC_MCR_AFM;
  ENET_MAC->MCR |= MAC_Config->AddressFilteringMode;

  /* VLAN Filtering Mode */
 	ENET_MAC->MCR |= (MAC_Config->VLANFilteringMode)<<15;

  /*Wrong Frame Pass */
  if (MAC_Config->PassWrongFrame == ENABLE) ENET_MAC->MCR |=MAC_MCR_PWF;
  else ENET_MAC->MCR &=~MAC_MCR_PWF;

  /* Late Collision Retransmission*/
  if (MAC_Config->LateCollision == ENABLE) ENET_MAC->MCR |=MAC_MCR_ELC;
  else ENET_MAC->MCR &=~MAC_MCR_ELC;

  /* Broadcast Frame Reception */
  if (MAC_Config->BroadcastFrameReception == ENABLE) ENET_MAC->MCR &=~MAC_MCR_DBF;
  else ENET_MAC->MCR |=MAC_MCR_DBF;

  /* PacketRetry */
  if (MAC_Config->PacketRetry == ENABLE) ENET_MAC->MCR &=~MAC_MCR_DPR;
  else ENET_MAC->MCR |=MAC_MCR_DPR;

  /* RxFrameFiltering */
  if (MAC_Config->RxFrameFiltering == ENABLE) ENET_MAC->MCR |=MAC_MCR_RVFF;
  else ENET_MAC->MCR &=~MAC_MCR_RVFF;

  /* AutomaticPadRemoval */
  if (MAC_Config->AutomaticPadRemoval == ENABLE) ENET_MAC->MCR |=MAC_MCR_APR;
  else ENET_MAC->MCR &=~MAC_MCR_APR;

  /* DefferalCheck */
  if (MAC_Config->DeferralCheck == ENABLE) ENET_MAC->MCR |=MAC_MCR_DCE;
  else ENET_MAC->MCR &=~MAC_MCR_DCE;

}



/*******************************************************************************
* Function Name  : ENET_SetOperatingMode
* Description    : Sets the Operating mode
* Input          : ENET_OperatingMode:(see ENET_OperatingMode in 91x_enet.h)
* Output         : None
* Return         : None
*******************************************************************************/
portBASE_TYPE ENET_SetOperatingMode( void )
{
unsigned long ulStatusReg, ulControlReg, ulLinkAbilityReg;

	/* Link status is latched, so read twice to get current value */
	ulStatusReg = ENET_MIIReadReg(0, STE100P_STATUS_REG);
	ulStatusReg = ENET_MIIReadReg(0, STE100P_STATUS_REG);

	if( !( ulStatusReg & STE100P_STATUS_LINKED ) )
	{	
		/* No Link. */
		return pdFAIL;
	}

	ulControlReg = ENET_MIIReadReg(0, STE100P_CONTROL_REG);
	if (ulControlReg & STE100P_AUTO_NEGOTIATE_ABILITY)
	{				
		/* AutoNegotiation is enabled. */
		if (!(ulStatusReg & STE100P_AUTO_NEGOTIATE_COMPLETE))
		{
			/* Auto-negotiation in progress. */
			return pdFAIL;				
		}		

		ulLinkAbilityReg = ENET_MIIReadReg(0, STE100P_LINK_ABILITY);
		if( ( ulLinkAbilityReg & STE100P_100FULL ) || ( ulLinkAbilityReg & STE100P_10FULL ) )
		{
			ENET_MAC->MCR |=MAC_MCR_FDM;   /* full duplex mode */
			ENET_MAC->MCR &=~MAC_MCR_DRO;  /* enable frame reception during transmission */
		}
		else
		{
			ENET_MAC->MCR &=~MAC_MCR_FDM; /* half duplex mode */
			ENET_MAC->MCR |=MAC_MCR_DRO;  /* disable frame reception during transmission */
		}
	}
	else
	{
		if( ulStatusReg & STE100P_CTRL_FULL )
		{
			ENET_MAC->MCR |=MAC_MCR_FDM;   /* full duplex mode */
			ENET_MAC->MCR &=~MAC_MCR_DRO;  /* enable frame reception during transmission */		
		}
		else
		{
			ENET_MAC->MCR &=~MAC_MCR_FDM; /* half duplex mode */
			ENET_MAC->MCR |=MAC_MCR_DRO;  /* disable frame reception during transmission */
		}
	}	
	
	return pdPASS;
}

/*******************************************************************************
* Function Name  : ENET_MIIWriteReg
* Description    : Writes a value on the PHY registers
* Input          : phyDev PHY device address
                 : phyReg PHY register to be written
*                : phyVal PHY register value
* Output         : None
* Return         : None
*******************************************************************************/
void ENET_MIIWriteReg (u8 phyDev, u8 phyReg, u32  phyVal)
{

  volatile u32 addr;
  volatile u32 res;     /* temporary result for address register status */
  volatile u32 timeout;

  /* Prepare the MII register address */
  addr = 0;
  addr |= ((phyDev<<11) & MAC_MII_ADDR_PHY_ADDR); /* set the PHY address */
  addr |= ((phyReg<<6) & MAC_MII_ADDR_MII_REG); /* select the corresponding register */
  addr |= MAC_MII_ADDR_MII_WRITE;  /* in write mode */
  addr |= MAC_MII_ADDR_MII_BUSY;

  /* Check for the Busy flag */
  timeout=0;
  do
  {
    timeout++;
    res = ENET_MAC->MIIA;
  } while ((res & MAC_MII_ADDR_MII_BUSY) && (timeout < (u32 )MII_WRITE_TO));

  /* Give the value to the MII data register */
  ENET_MAC->MIID = (phyVal & 0xFFFF);

  /* write the result value into the MII Address register */
  ENET_MAC->MIIA =addr;

  /* Check for the Busy flag */
  timeout=0;
  do
  {
    timeout++;
    res = ENET_MAC->MIIA;
  } while ((res & MAC_MII_ADDR_MII_BUSY) && (timeout < (u32 )MII_WRITE_TO));

}

/*******************************************************************************
* Function Name  : ENET_MIIReadReg
* Description    : Writes a value on the PHY
* Input          : phyDev PHY device address
*                : phyReg PHY register to be read
* Output         : None
* Return         : The read value (16 bits)
*******************************************************************************/
u32 ENET_MIIReadReg (u8 phyDev, u32 phyReg )
{

  u32 rValue;
  u32 addr;
  u32 res;     /* temporary result for address register status */
  u32 timeout; /* timeout value for read process */

  /* prepare the MII register address */
  addr = 0;
  addr |= ((phyDev<<11) & MAC_MII_ADDR_PHY_ADDR); /* set the PHY address */
  addr |= ((phyReg<<6) & MAC_MII_ADDR_MII_REG); /* select the corresponding register */
  addr &= ~(MAC_MII_ADDR_MII_WRITE);  /* ... in read mode */
  addr |= MAC_MII_ADDR_MII_BUSY;

  /* Check for the Busy flag */
  timeout = 0;

  do
  {
    timeout++;
    res = ENET_MAC->MIIA;
  } while ((res & MAC_MII_ADDR_MII_BUSY) && (timeout < (u32 )MII_READ_TO));

  /* write the result value into the MII Address register */
  ENET_MAC->MIIA = addr;

  /* Check for the Busy flag */
  timeout = 0;

  do
  {
    timeout++;
    res = ENET_MAC->MIIA;
  } while ((res & MAC_MII_ADDR_MII_BUSY) && (timeout < (u32 )MII_READ_TO));

  /* read the result value from data register*/
  rValue = ENET_MAC->MIID;

  return (rValue & 0x0000FFFF);
}

/*******************************************************************************
* Function Name  : ENET_RxDscrInit
* Description    : Initializes the Rx ENET descriptor chain. Single Descriptor
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/

void ENET_RxDscrInit(void)
{
int i;

	for( i = 0; i < ENET_NUM_RX_BUFFERS; i++ )
	{
		/* Assign temp Rx array to the ENET buffer */
		dmaRxDscrBase[ i ].dmaAddr = (u32)&(RxBuff[ i ][ 0 ]);

		/* Initialize RX ENET Status and control */
		dmaRxDscrBase[ i ].dmaStatCntl = 0x4000;

		/* Initialize the next descriptor- In our case its single descriptor */
		dmaRxDscrBase[ i ].dmaNext = (u32)&(dmaRxDscrBase[i+1]) | 0x01;

		/* Set the max packet size  */
		dmaRxDscrBase[ i ].dmaStatCntl = ENET_MAX_PACKET_SIZE | ENET_NEXT_ENABLE;

		/* Setting the VALID bit */
		dmaRxDscrBase[ i ].dmaPackStatus = DMA_DSCR_RX_STATUS_VALID_MSK;
	}

	dmaRxDscrBase[ ENET_NUM_RX_BUFFERS - 1 ].dmaNext = (u32)&(dmaRxDscrBase[ 0 ]);

	/* Setting the RX NEXT Descriptor Register inside the ENET */
	ENET_DMA->RXNDAR = (u32)&(dmaRxDscrBase) | 0x01;
}

/*******************************************************************************
* Function Name  : ENET_TxDscrInit
* Description    : Initializes the Tx ENET descriptor chain with single descriptor
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/

void ENET_TxDscrInit(void)
{

  /* ENET Start Address */
  dmaTxDscrBase.dmaAddr = (u32)TxBuff;

  /* Next Descriptor Address */
  dmaTxDscrBase.dmaNext = (u32)&(dmaTxDscrBase);

  /* Initialize ENET status and control */
  dmaTxDscrBase.dmaStatCntl = 0;

  /* Tx next set to Tx decriptor base */
  ENET_DMA->TXNDAR = (u32)&(dmaTxDscrBase);

  /* Enable next enable */
  ENET_DMA->TXNDAR |= DMA_DSCR_NXT_NPOL_EN;

}

/*******************************************************************************
* Function Name  : ENET_Init
* Description    : ENET MAC, PHY and DMA initializations
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void ENET_Init ()
{

  vu32 regValue;
  ENET_MACConfig *MAC_Config;
  ENET_MACConfig config;

  /* De-assert the SRESET bit of ENET + MAC devices */
  ENET_DMA->SCR &=~DMA_SCR_SRESET;
  MAC_Config =&config;
  /* Initialize MAC control register with common values */
  MAC_Config->ReceiveALL = DISABLE;
  if (SCU_GetHCLKFreqValue() > 50000)
  MAC_Config->MIIPrescaler = MIIPrescaler_2;
  MAC_Config->LoopbackMode = DISABLE;
  MAC_Config->AddressFilteringMode = MAC_Perfect_Multicast_Perfect;
	MAC_Config->VLANFilteringMode = VLANfilter_VLTAG;
  MAC_Config->PassWrongFrame = DISABLE;
  MAC_Config->LateCollision = DISABLE;
  MAC_Config->BroadcastFrameReception = ENABLE;
  MAC_Config->PacketRetry = ENABLE;
  MAC_Config->RxFrameFiltering = ENABLE;
  MAC_Config->AutomaticPadRemoval = ENABLE;
  MAC_Config->DeferralCheck = ENABLE;

    /* Configure MAC control register */
  ENET_MACControlConfig(MAC_Config);

  /* DMA initialization */
  /* Read the ENET DMA Status and Control Register */
  regValue = ENET_DMA->SCR;

  /* Setup Tx Max burst size */
  regValue &= ~(u32)DMA_SCR_TX_MAX_BURST_SZ;
  regValue |= (u32)DMA_SCR_TX_MAX_BURST_SZ_VAL;

  /* Setup Rx Max Burst size */
  regValue &= ~(u32)DMA_SCR_RX_MAX_BURST_SZ;
  regValue |= (u32)DMA_SCR_RX_MAX_BURST_SZ_VAL;

  /* Write Tx & Rx burst size to the ENET status and control register */
  ENET_DMA->SCR = regValue;

  /* Put the PHY in reset mode */
  ENET_MIIWriteReg(0x0,MAC_MII_REG_XCR, 0x8000);

  /* Delay to assure PHY reset */
  vTaskDelay( 3000 / portTICK_PERIOD_MS );

  /* initialize the opearting mode */
  while( ENET_SetOperatingMode() == pdFAIL )
  {
  		vTaskDelay( 3000 / portTICK_PERIOD_MS );
  }
	
  /*set MAC physical*/
	//ENET_MAC->MAH = (MAC_ADDR5<<8) + MAC_ADDR4;
	//ENET_MAC->MAL = (MAC_ADDR3<<24) + (MAC_ADDR2<<16) + (MAC_ADDR1<<8) + MAC_ADDR0;
	
  /* Initialize Rx and Tx descriptors in memory */
  ENET_TxDscrInit();
  ENET_RxDscrInit();

	// What's happening ???
#ifdef DEBUG
	//int pippo = 1; // Do NOT remove!!!
#endif
}

/********************************************************************************
* Function Name  : ENET_HandleRxPkt
* Description    : receive a packet and copy it to memory pointed by ppkt.
* Input          : ppkt: pointer on application receive buffer.
* Output         : None
* Return         : ENET_NOK - If there is no packet
*                : ENET_OK  - If there is a packet
*******************************************************************************/
u32 ENET_HandleRxPkt ( void *ppkt)
{
ENET_DMADSCRBase *pDescr;
u16 size;
static int iNextRx = 0;

	if( dmaRxDscrBase[ iNextRx ].dmaPackStatus & DMA_DSCR_RX_STATUS_VALID_MSK )
	{
		return 0;
	}

	pDescr = &dmaRxDscrBase[ iNextRx ];

	/*Get the size of the packet*/
	size = ((pDescr->dmaPackStatus & 0x7ff) - 4);

	//MEMCOPY_L2S_BY4((u8*)ppkt, RxBuff, size); /*optimized memcopy function*/
	memcpy(ppkt, RxBuff[iNextRx], size);   //string.h library*/

	/* Give the buffer back to ENET */
	pDescr->dmaPackStatus = DMA_DSCR_RX_STATUS_VALID_MSK;

	iNextRx++;

	if( iNextRx >= ENET_NUM_RX_BUFFERS )
	{
		iNextRx = 0;
	}

	/* Return no error */
	return size;
}

/*******************************************************************************
* Function Name  : ENET_TxPkt
* Description    : Transmit a packet
* Input          : ppkt: pointer to application packet Buffer
*                : size: Tx Packet size
* Output         : None
* Return         : None
*******************************************************************************/

u8 *pcGetNextBuffer( void )
{
	if( dmaTxDscrBase.dmaPackStatus & DMA_DSCR_TX_STATUS_VALID_MSK )
	{
		return NULL;
	}
	else
	{
		return ( unsigned char * ) TxBuff;
	}
}

void ENET_TxPkt(void *ppkt, u16 size)
{
	/* Setting the Frame Length*/
	dmaTxDscrBase.dmaStatCntl = (size&0xFFF);

	/* Start the ENET by setting the VALID bit in dmaPackStatus of current descr*/
	dmaTxDscrBase.dmaPackStatus = DMA_DSCR_TX_STATUS_VALID_MSK;

	/* Start the transmit operation */
	ENET_DMA->TXSTR|= DMA_TX_START_FETCH;
}

/*******************************************************************************
* Function Name  : ENET_Start
* Description    : Enables ENET MAC reception / transmission & starts DMA fetch
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/

void  ENET_Start ( void)
{
  u32 value;

  /* Force a ENET abort by software for the receive block */
   ENET_DMA->RXSTR &=~ DMA_RX_START_DMA_EN;

  /* Force a ENET abort by software for the transmit block */
   ENET_DMA->TXSTR &=~DMA_TX_START_DMA_EN;

  /* Reset all interrupts */
  ENET_DMA->ISR = 0xFFFFFFFF;

  /* Setup Descriptor Fetch ENET_PhyDelay for Receive Block */
  value = ENET_DMA->RXSTR;
  value &= ~( DMA_RX_START_DFETCH_DLY );
  value |= DMA_RX_START_DFETCH_DEFAULT;
  ENET_DMA->RXSTR=  value;

  /* Setup Descriptor Fetch ENET_PhyDelay for Transmit Block */
  value = ENET_DMA->TXSTR;
  value &= ~( DMA_TX_START_DFETCH_DLY );
  value |= DMA_TX_START_DFETCH_DEFAULT;
  ENET_DMA->TXSTR= value;

  /* Set Tx underrun bit */
  value &= ~( DMA_TX_START_URUN );
  value |= DMA_TX_START_URUN;
  ENET_DMA->TXSTR = value;

  /* Clear the interrupts */
  ENET_DMA->IER = 0x0;

  /* MAC TX enable */
  ENET_MAC->MCR|= MAC_MCR_TE;

  /* MAC RX enable */
  ENET_MAC->MCR|= MAC_MCR_RE;

  /* Start the DMA Fetch */
  ENET_DMA->RXSTR|= DMA_RX_START_FETCH;
}


/*******************************************************************************
* Function Name  : ENET_InitClocksGPIO
* Description    : Reset, clocks & GPIO Ethernet Pin initializations
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void ENET_InitClocksGPIO(void)
{

  GPIO_InitTypeDef GPIO_Struct;

  SCU_AHBPeriphClockConfig(__ENET, ENABLE);
  SCU_AHBPeriphReset(__ENET,DISABLE);
  SCU_PHYCLKConfig(ENABLE);

  GPIO_DeInit(GPIO1);
  GPIO_Struct.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 |GPIO_Pin_3 |GPIO_Pin_4 |GPIO_Pin_7 ;
  GPIO_Struct.GPIO_Type = GPIO_Type_PushPull;
  GPIO_Struct.GPIO_Direction = GPIO_PinOutput;
  GPIO_Struct.GPIO_IPConnected = GPIO_IPConnected_Disable;
  GPIO_Struct.GPIO_Alternate=GPIO_OutputAlt2;
  GPIO_Init(GPIO1, &GPIO_Struct);


  GPIO_DeInit(GPIO5);
  GPIO_Struct.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
  GPIO_Struct.GPIO_Type = GPIO_Type_PushPull;
  GPIO_Struct.GPIO_Direction = GPIO_PinOutput;
  GPIO_Struct.GPIO_IPConnected = GPIO_IPConnected_Disable;
  GPIO_Struct.GPIO_Alternate=GPIO_OutputAlt2;
  GPIO_Init(GPIO5, &GPIO_Struct);

}

/******************** (C) COPYRIGHT 2006 STMicroelectronics *******************/


