NXP LPC1768 Ethernet driver for lwip and CMSIS-RTOS

Dependents:   EthernetInterface EthernetInterface EthernetInterface_RSF EthernetInterface ... more

Legacy Networking Libraries

This is an mbed 2 networking library. For mbed 5, the networking libraries have been revised to better support additional network stacks and thread safety here.

This library is based on the code of the NXP LPC port of the Lightweight TCP/IP Stack

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.
Revision:
5:698d868a5285
Parent:
4:d827a085afd9
Child:
7:5754e05385b8
--- a/arch/lpc_phy_dp83848.c	Fri Mar 01 15:30:33 2013 +0000
+++ b/arch/lpc_phy_dp83848.c	Thu May 30 17:15:45 2013 +0100
@@ -1,11 +1,11 @@
 /**********************************************************************
-* $Id$        lpc_phy_dp83848.c            2011-11-20
+* $Id$		lpc_phy_dp83848.c			2011-11-20
 *//**
-* @file        lpc_phy_dp83848.c
-* @brief    DP83848C PHY status and control.
-* @version    1.0
-* @date        20 Nov. 2011
-* @author    NXP MCU SW Application Team
+* @file		lpc_phy_dp83848.c
+* @brief	DP83848C 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.
@@ -30,7 +30,7 @@
 #include "lpc_emac_config.h"
 #include "lpc_phy.h"
 
-/** @defgroup dp83848_phy    PHY status and control for the DP83848.
+/** @defgroup dp83848_phy	PHY status and control for the DP83848.
  * @ingroup lwip_phy
  *
  * Various functions for controlling and monitoring the status of the
@@ -44,6 +44,8 @@
 /** \brief  DP83848 PHY register offsets */
 #define DP8_BMCR_REG        0x0  /**< Basic Mode Control Register */
 #define DP8_BMSR_REG        0x1  /**< Basic Mode Status Reg */
+#define DP8_IDR1_REG        0x2  /**< Basic Mode Status Reg */
+#define DP8_IDR2_REG        0x3  /**< Basic Mode Status Reg */
 #define DP8_ANADV_REG       0x4  /**< Auto_Neg Advt Reg  */
 #define DP8_ANLPA_REG       0x5  /**< Auto_neg Link Partner Ability Reg */
 #define DP8_ANEEXP_REG      0x6  /**< Auto-neg Expansion Reg  */
@@ -52,6 +54,8 @@
 #define DP8_PHY_RBR_REG     0x17 /**< PHY RMII and Bypass Register  */
 #define DP8_PHY_STS_REG     0x19 /**< PHY Status Register  */
 
+#define DP8_PHY_SCSR_REG    0x1f /**< PHY Special Control/Status Register (LAN8720)  */
+
 /** \brief DP83848 Control register definitions */
 #define DP8_RESET          (1 << 15)  /**< 1= S/W Reset */
 #define DP8_LOOPBACK       (1 << 14)  /**< 1=loopback Enabled */
@@ -90,12 +94,25 @@
 #define DP8_PHYID1_OUI     0x2000     /**< Expected PHY ID1 */
 #define DP8_PHYID2_OUI     0x5c90     /**< Expected PHY ID2 */
 
+/** \brief LAN8720 PHY Special Control/Status Register */
+#define PHY_SCSR_100MBIT    0x0008    /**< Speed: 1=100 MBit, 0=10Mbit */
+#define PHY_SCSR_DUPLEX     0x0010    /**< PHY Duplex Mask             */
+
+/** \brief Link status bits */
+#define LNK_STAT_VALID       0x01 
+#define LNK_STAT_FULLDUPLEX  0x02
+#define LNK_STAT_SPEED10MPS  0x04
+
+/** \brief PHY ID definitions */
+#define DP83848C_ID         0x20005C90  /**< PHY Identifier - DP83848C */
+#define LAN8720_ID          0x0007C0F0  /**< PHY Identifier - LAN8720  */
+
 /** \brief PHY status structure used to indicate current status of PHY.
  */
 typedef struct {
-    u32_t     phy_speed_100mbs:1; /**< 10/100 MBS connection speed flag. */
-    u32_t     phy_full_duplex:1;  /**< Half/full duplex connection speed flag. */
-    u32_t     phy_link_active:1;  /**< Phy link active flag. */
+	u32_t     phy_speed_100mbs:1; /**< 10/100 MBS connection speed flag. */
+	u32_t     phy_full_duplex:1;  /**< Half/full duplex connection speed flag. */
+	u32_t     phy_link_active:1;  /**< Phy link active flag. */
 } PHY_STATUS_TYPE;
 
 /** \brief  PHY update flags */
@@ -107,6 +124,12 @@
 /** \brief  PHY update counter for state machine */
 static s32_t phyustate;
 
+/** \brief  Holds the PHY ID */
+static u32_t phy_id;
+
+/** \brief  Temporary holder of link status for LAN7420 */
+static u32_t phy_lan7420_sts_tmp;
+
 /** \brief  Update PHY status from passed value
  *
  *  This function updates the current PHY status based on the
@@ -119,61 +142,61 @@
  */
 static s32_t lpc_update_phy_sts(struct netif *netif, u32_t linksts)
 {
-    s32_t changed = 0;
+	s32_t changed = 0;
 
-    /* Update link active status */
-    if (linksts & DP8_VALID_LINK)
-        physts.phy_link_active = 1;
-    else
-        physts.phy_link_active = 0;
+	/* Update link active status */
+	if (linksts & LNK_STAT_VALID)
+		physts.phy_link_active = 1;
+	else
+		physts.phy_link_active = 0;
 
-    /* Full or half duplex */
-    if (linksts & DP8_FULLDUPLEX)
-        physts.phy_full_duplex = 1;
-    else
-        physts.phy_full_duplex = 0;
+	/* Full or half duplex */
+	if (linksts & LNK_STAT_FULLDUPLEX)
+		physts.phy_full_duplex = 1;
+	else
+		physts.phy_full_duplex = 0;
 
-    /* Configure 100MBit/10MBit mode. */
-    if (linksts & DP8_SPEED10MBPS)
-        physts.phy_speed_100mbs = 0;
-    else
-        physts.phy_speed_100mbs = 1;
+	/* Configure 100MBit/10MBit mode. */
+	if (linksts & LNK_STAT_SPEED10MPS)
+		physts.phy_speed_100mbs = 0;
+	else
+		physts.phy_speed_100mbs = 1;
 
-    if (physts.phy_speed_100mbs != olddphysts.phy_speed_100mbs) {
-        changed = 1;
-        if (physts.phy_speed_100mbs) {
-            /* 100MBit mode. */
-            lpc_emac_set_speed(1);
+	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, 100000000);
+		}
+		else {
+			/* 10MBit mode. */
+			lpc_emac_set_speed(0);
 
-            NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 10000000);
-        }
+			NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 10000000);
+		}
 
-        olddphysts.phy_speed_100mbs = physts.phy_speed_100mbs;
-    }
+		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);
+	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;
-    }
+		olddphysts.phy_full_duplex = physts.phy_full_duplex;
+	}
 
-    if (physts.phy_link_active != olddphysts.phy_link_active) {
-        changed = 1;
+	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);
+		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,
@@ -183,10 +206,10 @@
                 (void*) netif, 1);
 #endif
 
-        olddphysts.phy_link_active = physts.phy_link_active;
-    }
+		olddphysts.phy_link_active = physts.phy_link_active;
+	}
 
-    return changed;
+	return changed;
 }
 
 /** \brief  Initialize the DP83848 PHY.
@@ -202,81 +225,121 @@
  */
 err_t lpc_phy_init(struct netif *netif, int rmii)
 {
-    u32_t tmp;
-    s32_t i;
+	u32_t tmp;
+	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;
 
-    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 DP83848C in reset mode and wait for completion */
+	if (lpc_mii_write(DP8_BMCR_REG, DP8_RESET) != 0)
+		return ERR_TIMEOUT;
+	i = 400;
+	while (i > 0) {
+	    osDelay(1);   /* 1 ms */
+		if (lpc_mii_read(DP8_BMCR_REG, &tmp) != 0)
+			return ERR_TIMEOUT;
 
-    /* Only first read and write are checked for failure */
-    /* Put the DP83848C in reset mode and wait for completion */
-    if (lpc_mii_write(DP8_BMCR_REG, DP8_RESET) != 0)
-        return ERR_TIMEOUT;
-    i = 400;
-    while (i > 0) {
-        osDelay(1);   /* 1 ms */
-        if (lpc_mii_read(DP8_BMCR_REG, &tmp) != 0)
-            return ERR_TIMEOUT;
+		if (!(tmp & (DP8_RESET | DP8_POWER_DOWN)))
+			i = -1;
+		else
+			i--;
+	}
+	/* Timeout? */
+	if (i == 0)
+		return ERR_TIMEOUT;
 
-        if (!(tmp & (DP8_RESET | DP8_POWER_DOWN)))
-            i = -1;
-        else
-            i--;
-    }
-    /* Timeout? */
-    if (i == 0)
-        return ERR_TIMEOUT;
+	// read PHY ID
+	lpc_mii_read(DP8_IDR1_REG, &tmp);
+	phy_id = (tmp << 16);
+	lpc_mii_read(DP8_IDR2_REG, &tmp);    
+	phy_id |= (tmp & 0XFFF0);    
 
-    /* Setup link based on configuration options */
+	/* Setup link based on configuration options */
 #if PHY_USE_AUTONEG==1
-    tmp = DP8_AUTONEG;
+	tmp = DP8_AUTONEG;
 #else
-    tmp = 0;
+	tmp = 0;
 #endif
 #if PHY_USE_100MBS==1
-    tmp |= DP8_SPEED_SELECT;
+	tmp |= DP8_SPEED_SELECT;
 #endif
 #if PHY_USE_FULL_DUPLEX==1
-    tmp |= DP8_DUPLEX_MODE;
+	tmp |= DP8_DUPLEX_MODE;
 #endif
-    lpc_mii_write(DP8_BMCR_REG, tmp);
+	lpc_mii_write(DP8_BMCR_REG, tmp);
 
     /* Enable RMII mode for PHY */
     if (rmii)
         lpc_mii_write(DP8_PHY_RBR_REG, DP8_RBR_RMII_MODE);
 
-    /* The link is not set active at this point, but will be detected
+	/* The link is not set active at this point, but will be detected
        later */
 
-    return ERR_OK;
+	return ERR_OK;
 }
 
 /* Phy status update state machine */
 s32_t lpc_phy_sts_sm(struct netif *netif)
 {
-    s32_t changed = 0;
+	s32_t changed = 0;
+	u32_t data = 0;
+	u32_t tmp;
 
-    switch (phyustate) {
-        default:
-        case 0:
-            /* Read BMSR to clear faults */
-            lpc_mii_read_noblock(DP8_PHY_STAT_REG);
-            phyustate = 1;
-            break;
+	switch (phyustate) {
+		default:
+		case 0:
+			if (phy_id == DP83848C_ID) {    
+				lpc_mii_read_noblock(DP8_PHY_STAT_REG);
+				phyustate = 2;
+			}
+			else if (phy_id == LAN8720_ID) {
+				lpc_mii_read_noblock(DP8_PHY_SCSR_REG);
+				phyustate = 1;        
+			}
+			break;
+
+		case 1:
+			if (phy_id == LAN8720_ID) {
+				tmp = lpc_mii_read_data();
+				// we get speed and duplex here. 
+				phy_lan7420_sts_tmp =  (tmp & PHY_SCSR_DUPLEX)  ? LNK_STAT_FULLDUPLEX : 0;
+				phy_lan7420_sts_tmp |= (tmp & PHY_SCSR_100MBIT) ? 0 : LNK_STAT_SPEED10MPS;
 
-        case 1:
-            /* Wait for read status state */
-            if (!lpc_mii_is_busy()) {
-                /* Update PHY status */
-                changed = lpc_update_phy_sts(netif, lpc_mii_read_data());
-                phyustate = 0;
-            }
-            break;
-    }
+				//read the status register to get link status 
+				lpc_mii_read_noblock(DP8_BMSR_REG);
+				phyustate = 2;        
+			}
+			break;
+
+		case 2:
+			/* Wait for read status state */
+			if (!lpc_mii_is_busy()) {
+				/* Update PHY status */
+				tmp = lpc_mii_read_data();
 
-    return changed;
+				if (phy_id == DP83848C_ID) {
+					// STS register contains all needed status bits
+					data  = (tmp & DP8_VALID_LINK) ? LNK_STAT_VALID : 0;
+					data |= (tmp & DP8_FULLDUPLEX) ? LNK_STAT_FULLDUPLEX : 0;
+					data |= (tmp & DP8_SPEED10MBPS) ? LNK_STAT_SPEED10MPS : 0;
+				}
+				else if (phy_id == LAN8720_ID) {    
+					// we only get the link status here.
+					phy_lan7420_sts_tmp |= (tmp & DP8_LINK_STATUS) ? LNK_STAT_VALID : 0;
+					data = phy_lan7420_sts_tmp;          
+				}
+
+				changed = lpc_update_phy_sts(netif, data);        
+				phyustate = 0;                
+			}
+			break;
+	}
+
+	return changed;
 }
 
 /**