lwip 1.4 - DM9161A PHY

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lpc_phy_DM9161A.c Source File

lpc_phy_DM9161A.c

Go to the documentation of this file.
00001 /**********************************************************************
00002 * $Id$        lpc_phy_DM9161A.c            2013-01-28
00003 *//**
00004 * @file        lpc_phy_DM9161A.c
00005 * @brief       DM9161A PHY status and control.
00006 * @version     1.0
00007 * @date        14 Jan. 2013
00008 * @author      Frank Vannieuwkerke
00009 *              based on NXP MCU SW Application Team lpc_phy_dp83848.c
00010 *              Copyright(C) 2011, NXP Semiconductor
00011 *              All rights reserved.
00012 *
00013 *
00014 *
00015 * @NOTES:
00016 *  1. How to test : import http://mbed.org/users/mbed_official/code/TCPSocket_HelloWorld/ into the mbed compiler.
00017 *
00018 *  2. Open EthernetInterface\lwip-eth\arch folder
00019 *     Delete 'lpc_phy_dp83848.c'.
00020 *     Copy 'lpc_phy_DM9161A.c' (this file) into this folder.
00021 *
00022 *  3. When used with the Mini-DK hardware:
00023 *     Modify EthernetInterface\lwip-eth\arch\lpc_emac_config.h:
00024 *       Change #define LPC_PHYDEF_PHYADDR 1  to  #define LPC_PHYDEF_PHYADDR 19
00025 *
00026 *     Add following MAC address definition in main.cpp (before 'EthernetInterface eth;').
00027 *       extern "C" void mbed_mac_address(char * mac)
00028 *       {
00029 *       // define your own MAC Address
00030 *         mac[0] = 0x00;  
00031 *         mac[1] = 0x1F;  
00032 *         mac[2] = 0x33;  
00033 *         mac[3] = 0x42;  
00034 *         mac[4] = 0xFC;  
00035 *         mac[5] = 0x6F;           
00036 *       };
00037 *
00038 *
00039 *
00040 *
00041 ***********************************************************************
00042 * Software that is described herein is for illustrative purposes only
00043 * which provides customers with programming information regarding the
00044 * products. This software is supplied "AS IS" without any warranties.
00045 * NXP Semiconductors assumes no responsibility or liability for the
00046 * use of the software, conveys no license or title under any patent,
00047 * copyright, or mask work right to the product. NXP Semiconductors
00048 * reserves the right to make changes in the software without
00049 * notification. NXP Semiconductors also make no representation or
00050 * warranty that such application will be suitable for the specified
00051 * use without further testing or modification.
00052 **********************************************************************/
00053 
00054 #include "lwip/opt.h"
00055 #include "lwip/err.h"
00056 #include "lwip/tcpip.h"
00057 #include "lwip/snmp.h"
00058 #include "lpc_emac_config.h"
00059 #include "lpc_phy.h"
00060 
00061 /** @defgroup DM9161A_phy    PHY status and control for the DM9161A.
00062  * @ingroup lwip_phy
00063  *
00064  * Various functions for controlling and monitoring the status of the
00065  * DM9161A PHY. In polled (standalone) systems, the PHY state must be
00066  * monitored as part of the application. In a threaded (RTOS) system,
00067  * the PHY state is monitored by the PHY handler thread. The MAC
00068  * driver will not transmit unless the PHY link is active.
00069  * @{
00070  */
00071 
00072 /** \brief DM9161A PHY register offsets */
00073 #define DM9161A_BMCR_REG         0x00        /**< Basic Mode Control Register */
00074 #define DM9161A_BMSR_REG         0x01        /**< Basic Mode Status Reg */
00075 #define DM9161A_IDR1_REG         0x02        /**< PHY ID 1 Reg  */
00076 #define DM9161A_IDR2_REG         0x03        /**< PHY ID 2 Reg  */
00077 #define DM9161A_ANAR_REG         0x04        /**< Auto_Neg Advt Reg  */
00078 #define DM9161A_ANLPAR_REG       0x05        /**< Auto_neg Link Partner Ability Reg */
00079 #define DM9161A_ANER_REG         0x06        /**< Auto-neg Expansion Reg  */
00080 #define DM9161A_DSCR_REG         0x10        /**< Specified Configuration Reg */
00081 #define DM9161A_DSCSR_REG        0x11        /**< Specified Configuration and Status Reg */
00082 #define DM9161A_10BTCSR_REG      0x12        /**< 10BASE-T Configuration and Satus Reg */
00083 #define DM9161A_MDINTR_REG       0x15        /**< Specified Interrupt Reg */
00084 #define DM9161A_RECR_REG         0x16        /**< Specified Receive Error Counter Reg */
00085 #define DM9161A_DISCR_REG        0x17        /**< Specified Disconnect Counter Reg  */
00086 #define DM9161A_RLSR_REG         0x18        /**< Hardware Reset Latch State Reg  */
00087 
00088 /** \brief DM9161A BMCR register definitions */
00089 #define DM9161A_RESET            (1 << 15)   /**< 1= S/W Reset */
00090 #define DM9161A_LOOPBACK         (1 << 14)   /**< 1=loopback Enabled */
00091 #define DM9161A_SPEED_SELECT     (1 << 13)   /**< 1=Select 100MBps */
00092 #define DM9161A_AUTONEG          (1 << 12)   /**< 1=Enable auto-negotiation */ 
00093 #define DM9161A_POWER_DOWN       (1 << 11)   /**< 1=Power down PHY */
00094 #define DM9161A_ISOLATE          (1 << 10)   /**< 1=Isolate PHY */
00095 #define DM9161A_RESTART_AUTONEG  (1 << 9 )   /**< 1=Restart auto-negoatiation */
00096 #define DM9161A_DUPLEX_MODE      (1 << 8 )   /**< 1=Full duplex mode */
00097 #define DM9161A_COLLISION_TEST   (1 << 7 )   /**< 1=Perform collsion test */
00098 
00099 /** \brief DM9161A BMSR register definitions */
00100 #define DM9161A_100BASE_T4       (1 << 15)   /**< T4 mode */
00101 #define DM9161A_100BASE_TX_FD    (1 << 14)   /**< 100MBps full duplex */
00102 #define DM9161A_100BASE_TX_HD    (1 << 13)   /**< 100MBps half duplex */
00103 #define DM9161A_10BASE_T_FD      (1 << 12)   /**< 10MBps full duplex */
00104 #define DM9161A_10BASE_T_HD      (1 << 11)   /**< 10MBps half duplex */
00105 #define DM9161A_MF_PREAMB_SUPPR  (1 << 6 )   /**< Preamble suppress */
00106 #define DM9161A_AUTONEG_COMP     (1 << 5 )   /**< Auto-negotation complete */
00107 #define DM9161A_RMT_FAULT        (1 << 4 )   /**< Fault */
00108 #define DM9161A_AUTONEG_ABILITY  (1 << 3 )   /**< Auto-negotation supported */
00109 #define DM9161A_LINK_STATUS      (1 << 2 )   /**< 1=Link active */
00110 #define DM9161A_JABBER_DETECT    (1 << 1 )   /**< Jabber detect */
00111 #define DM9161A_EXTEND_CAPAB     (1 << 0 )   /**< Supports extended capabilities */
00112 
00113 /** \brief DM9161A ANAR and ANLPAR register definitions */
00114 #define DM9161A_NP               (1 << 15)   /**< No next page - always = 0 */
00115 #define DM9161A_ACK              (1 << 14)   /**< 1 = Link partner ability data reception acknowledged */
00116 #define DM9161A_RF               (1 << 13)   /**< 1 = Local device senses a fault condition */
00117 #define DM9161A_FCS              (1 << 10)   /**< 1 = Controller chip supports flow control ability */
00118 #define DM9161A_T4               (1 << 9 )   /**< No 100BASE-T4 is supported  - always = 0 */
00119 #define DM9161A_TX_FDX           (1 << 8 )   /**< 1 = 100BASE-TX full duplex is supported by the local device */
00120 #define DM9161A_TX_HDX           (1 << 7 )   /**< 1 = 100BASE-TX half duplex is supported by the local device */
00121 #define DM9161A_10_FDX           (1 << 6 )   /**< 1 = 10BASE-T full duplex is supported by the local device */
00122 #define DM9161A_10_HDX           (1 << 5 )   /**< 1 = 10BASE-T half duplex is supported by the local device */
00123 #define DM9161A_AN_IEEE_802_3    0x0001      /**< this device supports IEEE 802.3 CSMA/CD */
00124 
00125 /** \brief DM9161A ANER register definitions */
00126 #define DM9161A_PDF              (1 << 4 )   /**< 1 = A fault detected via parallel detection function */
00127 #define DM9161A_LP_NP_ABLE       (1 << 3 )   /**< 1 = Link partner, next page available */
00128 #define DM9161A_NP_ABLE          (1 << 2 )   /**< No next page - always = 0 */
00129 #define DM9161A_PAGE_RX          (1 << 1 )   /**< New page received - cleared when reg 6 is read */
00130 #define DM9161A_LP_AN_ABLE       (1 << 0 )   /**< 1 = Link partner supports auto-negotiation */
00131 
00132 /** \brief DM9161A DSCR register definitions */
00133 #define DM9161A_BP4B5B           (1 << 15)   /**< 1 = 4B5B encoder and 5B4B decoder function bypassed */
00134 #define DM9161A_BP_SCR           (1 << 14)   /**< 1 = Scrambler and descrambler function bypassed */
00135 #define DM9161A_BP_ALIGN         (1 << 13)   /**< 1 = Receive and Transmit functions disabled */
00136 #define DM9161A_BP_ADPOK         (1 << 12)   /**< 1 = Force signal detector (SD) active - ONLY FOR DEBUG */
00137 #define DM9161A_REPEATER         (1 << 11)   /**< 1 = Repeater mode - latched at power up reset */
00138 #define DM9161A_TX               (1 << 10)   /**< 1 = 100BASE-TX operation */
00139 #define DM9161A_RMII_ENABLE      (1 << 8 )   /**< 1 = Enable Reduced MII */
00140 #define DM9161A_F_LINK_100       (1 << 7 )   /**< 1 = Force 100Mbps good link status */
00141 #define DM9161A_SPLED_CTL        (1 << 6 )   /**< 1 = Disable SPEEDLED output and enable SD signal monitor - ONLY FOR DEBUG  */
00142 #define DM9161A_COLLED_CTL       (1 << 5 )   /**< 1 = FDX/COLLED output is configured to indicate Fullduplex Collision status */
00143 #define DM9161A_RPDCTR_EN        (1 << 4 )   /**< 1 = Enable automatic reduced power down */
00144 #define DM9161A_SM_RST           (1 << 3 )   /**< 1 = Reset state machine - auto cleared after reset */
00145 #define DM9161A_MFP_SC           (1 << 2 )   /**< 1 = MF preamble suppression bit on */
00146 #define DM9161A_SLEEP            (1 << 1 )   /**< 1 = sleep mode */
00147 #define DM9161A_RLOUT            (1 << 0 )   /**< 1 = 1, loop out the received data to the transmit channel */
00148 
00149 /** \brief DM9161A DSCSR register definitions */
00150 #define DM9161A_SPEEDMASK        (15 << 12)  /**< Speed and duplex mask */
00151 #define DM9161A_100FDX           (1 << 15)   /**< 1 = 100MB full duplex */
00152 #define DM9161A_100HDX           (1 << 14)   /**< 1 = 100MB half duplex */
00153 #define DM9161A_10FDX            (1 << 13)   /**< 1 = 10MB full duplex */
00154 #define DM9161A_10HDX            (1 << 12)   /**< 1 = 10MB half duplex */
00155 
00156 /** \brief DM9161A 10BTCSR register definitions */
00157 #define DM9161A_LP_EN            (1 << 14)   /**< 1 = Transmission of link pulses enabled */
00158 #define DM9161A_HBE              (1 << 13)   /**< 1 = Heartbeat function enabled */
00159 #define DM9161A_SQUELCH          (1 << 12)   /**< 1 = normal squelch */
00160 #define DM9161A_JABEN            (1 << 11)   /**< 1 = Jabber function enabled */
00161 #define DM9161A_10BT_SER         (1 << 10)   /**< 1 = 10BASE-T GPSI mode selected */
00162 #define DM9161A_POLR             (1 << 0 )   /**< 1 = 10Mbps cable polarity is reversed */
00163 
00164 /** \brief DM9161A MDINTR register definitions */
00165 #define DM9161A_INTR_PEND        (1 << 15)   /**< Interrupt pending */
00166 #define DM9161A_FDX_MASK         (1 << 11)   /**< Full-duplex interrupt mask */
00167 #define DM9161A_SPD_MASK         (1 << 10)   /**< Speed interrupt mask */
00168 #define DM9161A_LINK_MASK        (1 << 9 )   /**< Link interrupt mask */
00169 #define DM9161A_INTR_MASK        (1 << 8 )   /**< Master interrupt mask */
00170 #define DM9161A_FDX_CHANGE       (1 << 4 )   /**< 1 = indicates a change of duplex since last register read */
00171 #define DM9161A_SPD_CHANGE       (1 << 3 )   /**< 1 = indicates a change of speed since last register read */
00172 #define DM9161A_LINK_CHANGE      (1 << 2 )   /**< 1 = indicates a change of link since last register read */
00173 #define DM9161A_INTR_STATUS      (1 << 0 )   /**< 1 = indicates that the interrupt mask is off */
00174 
00175 /** \brief DM9161A RLSR register definitions */
00176 #define DM9161A_LH_LEDMODE       (1 << 15)   /**< LEDMODE pin reset latch value */
00177 #define DM9161A_LH_MDINTR        (1 << 14)   /**< MDINTR pin reset latch value */
00178 #define DM9161A_LH_CSTS          (1 << 13)   /**< CABLESTS pin reset latch value */
00179 #define DM9161A_LH_ISO           (1 << 12)   /**< TXCLK pin reset latch value */
00180 #define DM9161A_LH_RMII          (1 << 11)   /**< COL pin reset latch value */
00181 #define DM9161A_LH_TP10SER       (1 << 10)   /**< RXCLK pin reset latch value */
00182 #define DM9161A_LH_REPTR         (1 << 9)    /**< RXER pin reset latch value */
00183 #define DM9161A_LH_TSTMOD        (1 << 8 )   /**< RXDV pin reset latch value */
00184 #define DM9161A_LH_OP2           (1 << 7 )   /**< LINKLED pin reset latch value */
00185 #define DM9161A_LH_OP1           (1 << 6 )   /**< SPOLED pin reset latch value */
00186 #define DM9161A_LH_OP0           (1 << 5 )   /**< FDXLED pin reset latch value */
00187 #define DM9161A_LH_PH4           (1 << 4 )   /**< CRS pin reset latch value */
00188 #define DM9161A_LH_PH3           (1 << 3 )   /**< RXD3 pin reset latch value */
00189 #define DM9161A_LH_PH2           (1 << 2 )   /**< RXD2 pin reset latch value */
00190 #define DM9161A_LH_PH1           (1 << 1 )   /**< RXD1 pin reset latch value */
00191 #define DM9161A_LH_PH0           (1 << 0 )   /**< RXD0 pin reset latch value */
00192 
00193 #define DM9161A_FULLD_100M        0x2100      /**< Full Duplex 100Mbit               */
00194 #define DM9161A_HALFD_100M        0x2000      /**< Half Duplex 100Mbit               */
00195 #define DM9161A_FULLD_10M         0x0100      /**< Full Duplex 10Mbit                */
00196 #define DM9161A_HALFD_10M         0x0000      /**< Half Duplex 10MBit                */
00197 #define DM9161A_AUTO_NEG          0x3000      /**< Select Auto Negotiation           */
00198 #define DM9161A_AUTO_NEG_MASK     0xEFFF      /**< Auto Negotiation mask bit         */
00199 
00200 /** \brief DM9161A PHY ID register definitions */
00201 #define DM9161A_PHYID1_OUI        0x0181      /**< Expected PHY ID1 */
00202 #define DM9161A_PHYID2_OUI        0xB8A0      /**< Expected PHY ID2 */
00203 
00204 #define DM9161A_DEF_ADR           0x1300      /**< Default PHY device address DM9161A */
00205 
00206 /** \brief PHY status structure used to indicate current status of PHY.
00207  */
00208 typedef struct {
00209     u32_t     phy_speed_100mbs:2; /**< 10/100 MBS connection speed flag. */
00210     u32_t     phy_full_duplex:2;  /**< Half/full duplex connection speed flag. */
00211     u32_t     phy_link_active:2;  /**< Phy link active flag. */
00212 } PHY_STATUS_TYPE;
00213 
00214 /** \brief  PHY update flags */
00215 static PHY_STATUS_TYPE physts;
00216 
00217 /** \brief  Last PHY update flags, used for determing if something has changed */
00218 static PHY_STATUS_TYPE olddphysts;
00219 
00220 /** \brief  PHY update counter for state machine */
00221 static s32_t phyustate;
00222 
00223 /** \brief  Update PHY status from passed value
00224  *
00225  *  This function updates the current PHY status based on the
00226  *  passed PHY status word. The PHY status indicate if the link
00227  *  is active, the connection speed, and duplex.
00228  *
00229  *  \param[in]    netif   NETIF structure
00230  *  \param[in]    linksts Status word with link state
00231  *  \param[in]    sdsts   Status word with speed and duplex states
00232  *  \return        1 if the status has changed, otherwise 0
00233  */
00234 static s32_t lpc_update_phy_sts(struct netif *netif, u32_t linksts, u32_t sdsts)
00235 {
00236     s32_t changed = 0;
00237 
00238 //    sdsts &= DM9161A_AUTO_NEG_MASK; // mask DM9161A_AUTO_NEG
00239 
00240     /* Update link active status */
00241     if (linksts & DM9161A_LINK_STATUS)
00242         physts.phy_link_active = 1;
00243     else
00244         physts.phy_link_active = 0;
00245 
00246     /* Full or half duplex */
00247     if (sdsts & DM9161A_DUPLEX_MODE)
00248         physts.phy_full_duplex = 1;
00249     else
00250         physts.phy_full_duplex = 0;
00251 
00252     /* Configure 100MBit/10MBit mode. */
00253     if (sdsts & DM9161A_SPEED_SELECT)
00254         physts.phy_speed_100mbs = 1;
00255     else
00256         physts.phy_speed_100mbs = 0;
00257 
00258     if (physts.phy_speed_100mbs != olddphysts.phy_speed_100mbs) {
00259         changed = 1;
00260         if (physts.phy_speed_100mbs) {
00261             /* 100MBit mode. */
00262             lpc_emac_set_speed(1);
00263 
00264             NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100000000);
00265         }
00266         else {
00267             /* 10MBit mode. */
00268             lpc_emac_set_speed(0);
00269 
00270             NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 10000000);
00271         }
00272 
00273         olddphysts.phy_speed_100mbs = physts.phy_speed_100mbs;
00274     }
00275 
00276     if (physts.phy_full_duplex != olddphysts.phy_full_duplex) {
00277         changed = 1;
00278         if (physts.phy_full_duplex)
00279             lpc_emac_set_duplex(1);
00280         else
00281             lpc_emac_set_duplex(0);
00282 
00283         olddphysts.phy_full_duplex = physts.phy_full_duplex;
00284     }
00285 
00286     if (physts.phy_link_active != olddphysts.phy_link_active) {
00287         changed = 1;
00288 #if NO_SYS == 1
00289         if (physts.phy_link_active)
00290             netif_set_link_up(netif);
00291         else
00292             netif_set_link_down(netif);
00293 #else
00294         if (physts.phy_link_active)
00295             tcpip_callback_with_block((tcpip_callback_fn) netif_set_link_up,
00296                 (void*) netif, 1);
00297          else
00298             tcpip_callback_with_block((tcpip_callback_fn) netif_set_link_down,
00299                 (void*) netif, 1);
00300 #endif
00301 
00302         olddphysts.phy_link_active = physts.phy_link_active;
00303     }
00304 
00305     return changed;
00306 }
00307 
00308 /** \brief  Initialize the DM9161A PHY.
00309  *
00310  *  This function initializes the DM9161A PHY. It will block until
00311  *  complete. This function is called as part of the EMAC driver
00312  *  initialization. Configuration of the PHY at startup is
00313  *  controlled by setting up configuration defines in lpc_phy.h.
00314  *
00315  *  \param[in]     netif   NETIF structure
00316  *  \param[in]     rmii    If set, configures the PHY for RMII mode
00317  *  \return         ERR_OK if the setup was successful, otherwise ERR_TIMEOUT
00318  */
00319 err_t lpc_phy_init(struct netif *netif, int rmii)
00320 {
00321     u32_t tmp;
00322     s32_t i;
00323 
00324     physts.phy_speed_100mbs = olddphysts.phy_speed_100mbs = 2;
00325     physts.phy_full_duplex = olddphysts.phy_full_duplex = 2;
00326     physts.phy_link_active = olddphysts.phy_link_active = 2;
00327     phyustate = 0;
00328 
00329     /* Only first read and write are checked for failure */
00330     /* Put the DM9161A in reset mode and wait for completion */
00331     if (lpc_mii_write(DM9161A_BMCR_REG, DM9161A_RESET) != 0)
00332         return ERR_TIMEOUT;
00333     i = 400;
00334     while (i > 0) {
00335         osDelay(1);   // 1 ms
00336         if (lpc_mii_read(DM9161A_BMCR_REG, &tmp) != 0)
00337             return ERR_TIMEOUT;
00338 
00339         if (!(tmp & (DM9161A_RESET | DM9161A_POWER_DOWN)))
00340             i = -1;
00341         else
00342             i--;
00343     }
00344     // Timeout?
00345     if (i == 0)
00346         return ERR_TIMEOUT;
00347 
00348     /* Setup link based on configuration options */
00349 #if PHY_USE_AUTONEG==1
00350     tmp = DM9161A_AUTONEG | DM9161A_RESTART_AUTONEG;
00351 #else
00352     tmp = 0;
00353 #endif 
00354 #if PHY_USE_100MBS==1
00355     tmp |= DM9161A_SPEED_SELECT;
00356 #endif
00357 #if PHY_USE_FULL_DUPLEX==1
00358     tmp |= DM9161A_DUPLEX_MODE;
00359 #endif
00360 
00361     lpc_mii_write(DM9161A_BMCR_REG, tmp);
00362 
00363     /* Wait for autonegotiation completion */
00364     i = 400;
00365     while (i > 0)
00366     {
00367         osDelay(1);   // 1 ms
00368         if (lpc_mii_read(DM9161A_BMSR_REG, &tmp) != 0)
00369         {
00370             printf("Timeout\n");
00371             return ERR_TIMEOUT;
00372         }
00373         if (tmp & (DM9161A_AUTONEG_COMP))
00374             i = -1;
00375         else
00376             i--;
00377     }
00378     // Timeout?
00379     if (i == 0)
00380     {
00381         printf("Timeout\n");
00382         return ERR_TIMEOUT;
00383     }
00384 
00385     /* Enable RMII mode for PHY  - NOT NEEDED FOR MIDI-DK - RMII pin is lathed on reset*/
00386 /*    if (rmii)
00387         lpc_mii_write(DM9161A_DSCR_REG, DM9161A_RMII_ENABLE);
00388 */
00389     /* The link is not set active at this point, but will be detected
00390        later */
00391 
00392     return ERR_OK;
00393 }
00394 
00395 /* Phy status update state machine */
00396 s32_t lpc_phy_sts_sm(struct netif *netif)
00397 {
00398     static u32_t sts;
00399     s32_t changed = 0;
00400     switch (phyustate)
00401     {
00402         default:
00403         case 0:
00404             // Read BMSR to clear faults
00405             lpc_mii_read_noblock(DM9161A_BMSR_REG);
00406             phyustate = 1;
00407             break;
00408 
00409         case 1:
00410             // Wait for read status state
00411             if (!lpc_mii_is_busy())
00412             {
00413                 // Get autonegotiation complete bit
00414                 sts = lpc_mii_read_data();
00415                 lpc_mii_read_noblock(DM9161A_BMCR_REG);
00416                 phyustate = 2;
00417             }
00418             break;
00419 
00420         case 2:
00421             // Wait for read status state
00422             if (!lpc_mii_is_busy())
00423             {
00424                 // Update PHY status (BMCR contains speed and duplex state)
00425                 changed = lpc_update_phy_sts(netif, sts, lpc_mii_read_data());
00426                 phyustate = 0;
00427             }
00428             break;
00429     }
00430     return changed;
00431 }
00432 
00433 /* //Original state machine code
00434 */
00435 
00436 
00437 
00438 /**
00439  * @}
00440  */
00441 
00442 /* --------------------------------- End Of File ------------------------------ */