Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: EthernetInterface EthernetInterface_vz
Fork of lwip-eth by
Diff: arch/lpc_phy_dp83848.c
- Revision:
- 5:698d868a5285
- Parent:
- 4:d827a085afd9
- Child:
- 7:5754e05385b8
diff -r d827a085afd9 -r 698d868a5285 arch/lpc_phy_dp83848.c
--- 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;
}
/**
