302 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			302 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /**********************************************************************
 | |
| * $Id$		lpc_phy_lan8720.c			2011-11-20
 | |
| *//**
 | |
| * @file		lpc_phy_lan8720.c
 | |
| * @brief	LAN8720 PHY status and control.
 | |
| * @version	1.0
 | |
| * @date		20 Nov. 2011
 | |
| * @author	NXP MCU SW Application Team
 | |
| * 
 | |
| * Copyright(C) 2011, NXP Semiconductor
 | |
| * All rights reserved.
 | |
| *
 | |
| ***********************************************************************
 | |
| * Software that is described herein is for illustrative purposes only
 | |
| * which provides customers with programming information regarding the
 | |
| * products. This software is supplied "AS IS" without any warranties.
 | |
| * NXP Semiconductors assumes no responsibility or liability for the
 | |
| * use of the software, conveys no license or title under any patent,
 | |
| * copyright, or mask work right to the product. NXP Semiconductors
 | |
| * reserves the right to make changes in the software without
 | |
| * notification. NXP Semiconductors also make no representation or
 | |
| * warranty that such application will be suitable for the specified
 | |
| * use without further testing or modification.
 | |
| **********************************************************************/
 | |
| 
 | |
| #include "lwip/opt.h"
 | |
| #include "lwip/err.h"
 | |
| #include "lwip/tcpip.h"
 | |
| #include "lwip/snmp.h"
 | |
| 
 | |
| #include "boards/board.h"
 | |
| #include "arch/lpc_arch.h" // FIXME Ethernet
 | |
| #include "lpc_phy.h"
 | |
| 
 | |
| /** @defgroup lan8720_phy	PHY status and control for the LAN8720.
 | |
|  * @ingroup lwip_phy
 | |
|  *
 | |
|  * Various functions for controlling and monitoring the status of the
 | |
|  * LAN8720 PHY. In polled (standalone) systems, the PHY state must be
 | |
|  * monitored as part of the application. In a threaded (RTOS) system,
 | |
|  * the PHY state is monitored by the PHY handler thread. The MAC
 | |
|  * driver will not transmit unless the PHY link is active.
 | |
|  * @{
 | |
|  */
 | |
| 
 | |
| /** \brief  LAN8720 PHY register offsets */
 | |
| #define LAN8_BCR_REG        0x0  /**< Basic Control Register */
 | |
| #define LAN8_BSR_REG        0x1  /**< Basic Status Reg */
 | |
| #define LAN8_PHYID1_REG     0x2  /**< PHY ID 1 Reg  */
 | |
| #define LAN8_PHYID2_REG     0x3  /**< PHY ID 2 Reg */
 | |
| #define LAN8_PHYSPLCTL_REG  0x1F /**< PHY special control/status Reg */
 | |
| 
 | |
| /* LAN8720 BCR register definitions */
 | |
| #define LAN8_RESET          (1 << 15)  /**< 1= S/W Reset */
 | |
| #define LAN8_LOOPBACK       (1 << 14)  /**< 1=loopback Enabled */
 | |
| #define LAN8_SPEED_SELECT   (1 << 13)  /**< 1=Select 100MBps */
 | |
| #define LAN8_AUTONEG        (1 << 12)  /**< 1=Enable auto-negotiation */
 | |
| #define LAN8_POWER_DOWN     (1 << 11)  /**< 1=Power down PHY */
 | |
| #define LAN8_ISOLATE        (1 << 10)  /**< 1=Isolate PHY */
 | |
| #define LAN8_RESTART_AUTONEG (1 << 9)  /**< 1=Restart auto-negoatiation */
 | |
| #define LAN8_DUPLEX_MODE    (1 << 8)   /**< 1=Full duplex mode */
 | |
| 
 | |
| /* LAN8720 BSR register definitions */
 | |
| #define LAN8_100BASE_T4     (1 << 15)  /**< T4 mode */
 | |
| #define LAN8_100BASE_TX_FD  (1 << 14)  /**< 100MBps full duplex */
 | |
| #define LAN8_100BASE_TX_HD  (1 << 13)  /**< 100MBps half duplex */
 | |
| #define LAN8_10BASE_T_FD    (1 << 12)  /**< 100Bps full duplex */
 | |
| #define LAN8_10BASE_T_HD    (1 << 11)  /**< 10MBps half duplex */
 | |
| #define LAN8_AUTONEG_COMP   (1 << 5)   /**< Auto-negotation complete */
 | |
| #define LAN8_RMT_FAULT      (1 << 4)   /**< Fault */
 | |
| #define LAN8_AUTONEG_ABILITY (1 << 3)  /**< Auto-negotation supported */
 | |
| #define LAN8_LINK_STATUS    (1 << 2)   /**< 1=Link active */
 | |
| #define LAN8_JABBER_DETECT  (1 << 1)   /**< Jabber detect */
 | |
| #define LAN8_EXTEND_CAPAB   (1 << 0)   /**< Supports extended capabilities */
 | |
| 
 | |
| /* LAN8720 PHYSPLCTL status definitions */
 | |
| #define LAN8_SPEEDMASK      (7 << 2)   /**< Speed and duplex mask */
 | |
| #define LAN8_SPEED100F      (6 << 2)   /**< 100BT full duplex */
 | |
| #define LAN8_SPEED10F       (5 << 2)   /**< 10BT full duplex */
 | |
| #define LAN8_SPEED100H      (2 << 2)   /**< 100BT half duplex */
 | |
| #define LAN8_SPEED10H       (1 << 2)   /**< 10BT half duplex */
 | |
| 
 | |
| /* LAN8720 PHY ID 1/2 register definitions */
 | |
| #define LAN8_PHYID1_OUI     0x0007     /**< Expected PHY ID1 */
 | |
| #define LAN8_PHYID2_OUI     0xC0F0     /**< Expected PHY ID2, except last 4 bits */
 | |
| 
 | |
| /**
 | |
|  * @brief PHY status structure used to indicate current status of PHY.
 | |
|  */
 | |
| typedef struct {
 | |
| 	u32_t     phy_speed_100mbs:2; /**< 10/100 MBS connection speed flag. */
 | |
| 	u32_t     phy_full_duplex:2;  /**< Half/full duplex connection speed flag. */
 | |
| 	u32_t     phy_link_active:2;  /**< Phy link active flag. */
 | |
| } PHY_STATUS_TYPE;
 | |
| 
 | |
| /** \brief  PHY update flags */
 | |
| static PHY_STATUS_TYPE physts;
 | |
| 
 | |
| /** \brief  Last PHY update flags, used for determing if something has changed */
 | |
| static PHY_STATUS_TYPE olddphysts;
 | |
| 
 | |
| /** \brief  PHY update counter for state machine */
 | |
| static s32_t phyustate;
 | |
| 
 | |
| /** \brief  Update PHY status from passed value
 | |
|  *
 | |
|  *  This function updates the current PHY status based on the
 | |
|  *  passed PHY status word. The PHY status indicate if the link
 | |
|  *  is active, the connection speed, and duplex.
 | |
|  *
 | |
|  *  \param[in]    netif   NETIF structure
 | |
|  *  \param[in]    linksts Status word with link state
 | |
|  *  \param[in]    sdsts   Status word with speed and duplex states
 | |
|  *  \return        1 if the status has changed, otherwise 0
 | |
|  */
 | |
| static s32_t lpc_update_phy_sts(struct netif *netif, u32_t linksts, u32_t sdsts)
 | |
| {
 | |
| 	s32_t changed = 0;
 | |
| 
 | |
| 	/* Update link active status */
 | |
| 	if (linksts & LAN8_LINK_STATUS)
 | |
| 		physts.phy_link_active = 1;
 | |
| 	else
 | |
| 		physts.phy_link_active = 0;
 | |
| 
 | |
| 	switch (sdsts & LAN8_SPEEDMASK) {
 | |
| 		case LAN8_SPEED100F:
 | |
| 		default:
 | |
| 			physts.phy_speed_100mbs = 1;
 | |
| 			physts.phy_full_duplex = 1;
 | |
| 			break;
 | |
| 
 | |
| 		case LAN8_SPEED10F:
 | |
| 			physts.phy_speed_100mbs = 0;
 | |
| 			physts.phy_full_duplex = 1;
 | |
| 			break;
 | |
| 
 | |
| 		case LAN8_SPEED100H:
 | |
| 			physts.phy_speed_100mbs = 1;
 | |
| 			physts.phy_full_duplex = 0;
 | |
| 			break;
 | |
| 
 | |
| 		case LAN8_SPEED10H:
 | |
| 			physts.phy_speed_100mbs = 0;
 | |
| 			physts.phy_full_duplex = 0;
 | |
| 			break;
 | |
| 	}
 | |
| 
 | |
| 	if (physts.phy_speed_100mbs != olddphysts.phy_speed_100mbs) {
 | |
| 		changed = 1;
 | |
| 		if (physts.phy_speed_100mbs) {
 | |
| 			/* 100MBit mode. */
 | |
| 			lpc_emac_set_speed(1);
 | |
| 
 | |
| 			NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100000000);
 | |
| 		}
 | |
| 		else {
 | |
| 			/* 10MBit mode. */
 | |
| 			lpc_emac_set_speed(0);
 | |
| 
 | |
| 			NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 10000000);
 | |
| 		}
 | |
| 
 | |
| 		olddphysts.phy_speed_100mbs = physts.phy_speed_100mbs;
 | |
| 	}
 | |
| 
 | |
| 	if (physts.phy_full_duplex != olddphysts.phy_full_duplex) {
 | |
| 		changed = 1;
 | |
| 		if (physts.phy_full_duplex)
 | |
| 			lpc_emac_set_duplex(1);
 | |
| 		else
 | |
| 			lpc_emac_set_duplex(0);
 | |
| 
 | |
| 		olddphysts.phy_full_duplex = physts.phy_full_duplex;
 | |
| 	}
 | |
| 
 | |
| 	if (physts.phy_link_active != olddphysts.phy_link_active) {
 | |
| 		changed = 1;
 | |
| #if NO_SYS == 1
 | |
| 		if (physts.phy_link_active)
 | |
|             netif_set_link_up(netif);
 | |
| 		else
 | |
| 			netif_set_link_down(netif);
 | |
| #else
 | |
| 		if (physts.phy_link_active)
 | |
|             tcpip_callback_with_block((tcpip_callback_fn) netif_set_link_up,
 | |
|                 (void*) netif, 1);
 | |
|          else
 | |
|             tcpip_callback_with_block((tcpip_callback_fn) netif_set_link_down,
 | |
|                 (void*) netif, 1);
 | |
| #endif
 | |
| 
 | |
| 		olddphysts.phy_link_active = physts.phy_link_active;
 | |
| 	}
 | |
| 
 | |
| 	return changed;
 | |
| }
 | |
| 
 | |
| /** \brief  Initialize the LAN8720 PHY.
 | |
|  *
 | |
|  *  This function initializes the LAN8720 PHY. It will block until
 | |
|  *  complete. This function is called as part of the EMAC driver
 | |
|  *  initialization. Configuration of the PHY at startup is
 | |
|  *  controlled by setting up configuration defines in
 | |
|  *  lpc_emac_config.h.
 | |
|  *
 | |
|  *  \param[in]     netif   NETIF structure
 | |
|  *  \param[in]     rmii    If set, configures the PHY for RMII mode
 | |
|  *  \return        ERR_OK if the setup was successful, otherwise ERR_TIMEOUT
 | |
|  */
 | |
| err_t lpc_phy_init(struct netif *netif, int rmii)
 | |
| {
 | |
| 	u32_t tmp, tmp1;
 | |
| 	s32_t i;
 | |
| 
 | |
| 	physts.phy_speed_100mbs = olddphysts.phy_speed_100mbs = 2;
 | |
| 	physts.phy_full_duplex = olddphysts.phy_full_duplex = 2;
 | |
| 	physts.phy_link_active = olddphysts.phy_link_active = 2;
 | |
| 	phyustate = 0;
 | |
| 
 | |
| 	/* Only first read and write are checked for failure */
 | |
| 	/* Put the LAN8720 in reset mode and wait for completion */
 | |
| 	if (lpc_mii_write(LAN8_BCR_REG, LAN8_RESET) != 0)
 | |
| 		return ERR_TIMEOUT;
 | |
| 	i = 400;
 | |
| 	while (i > 0) {
 | |
| 		msDelay(1);   /* 1 ms */
 | |
| 		if (lpc_mii_read(LAN8_BCR_REG, &tmp) != 0)
 | |
| 			return ERR_TIMEOUT;
 | |
| 
 | |
| 		if (!(tmp & (LAN8_RESET | LAN8_POWER_DOWN)))
 | |
| 			i = -1;
 | |
| 		else
 | |
| 			i--;
 | |
| 	}
 | |
| 	/* Timeout? */
 | |
| 	if (i == 0)
 | |
| 		return ERR_TIMEOUT;
 | |
| 
 | |
| 	/* Setup link based on configuration options */
 | |
| #if PHY_USE_AUTONEG==1
 | |
| 	tmp = LAN8_AUTONEG;
 | |
| #else
 | |
| 	tmp = 0;
 | |
| #endif
 | |
| #if PHY_USE_100MBS==1
 | |
| 	tmp |= LAN8_SPEED_SELECT;
 | |
| #endif
 | |
| #if PHY_USE_FULL_DUPLEX==1
 | |
| 	tmp |= LAN8_DUPLEX_MODE;
 | |
| #endif
 | |
| 	lpc_mii_write(LAN8_BCR_REG, tmp);
 | |
| 
 | |
| 	/* The link is not set active at this point, but will be detected
 | |
|        later */
 | |
| 
 | |
| 	return ERR_OK;
 | |
| }
 | |
| 
 | |
| /* Phy status update state machine */
 | |
| s32_t lpc_phy_sts_sm(struct netif *netif)
 | |
| {
 | |
| 	static u32_t sts;
 | |
| 	s32_t changed = 0;
 | |
| 
 | |
| 	switch (phyustate) {
 | |
| 		default:
 | |
| 		case 0:
 | |
| 			/* Read BMSR to clear faults */
 | |
| 			lpc_mii_read_noblock(LAN8_BSR_REG);
 | |
| 			phyustate = 1;
 | |
| 			break;
 | |
| 
 | |
| 		case 1:
 | |
| 			/* Wait for read status state */
 | |
| 			if (!lpc_mii_is_busy()) {
 | |
| 				/* Get PHY status with link state */
 | |
| 				sts = lpc_mii_read_data();
 | |
| 				lpc_mii_read_noblock(LAN8_PHYSPLCTL_REG);
 | |
| 				phyustate = 2;
 | |
| 			}
 | |
| 			break;
 | |
| 
 | |
| 		case 2:
 | |
| 			/* Wait for read status state */
 | |
| 			if (!lpc_mii_is_busy()) {
 | |
| 				/* Update PHY status */
 | |
| 				changed = lpc_update_phy_sts(netif, sts, lpc_mii_read_data());
 | |
| 				phyustate = 0;
 | |
| 			}
 | |
| 			break;
 | |
| 	}
 | |
| 
 | |
| 	return changed;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @}
 | |
|  */
 | |
| 
 | |
| /* --------------------------------- End Of File ------------------------------ */
 | 
