Sergey Pastor / 1

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers rtl8211.c Source File

rtl8211.c

Go to the documentation of this file.
00001 /**
00002  * @file rtl8211.c
00003  * @brief RTL8211 Ethernet PHY transceiver
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneTCP Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00026  * @version 1.7.6
00027  **/
00028 
00029 //Switch to the appropriate trace level
00030 #define TRACE_LEVEL NIC_TRACE_LEVEL
00031 
00032 //Dependencies
00033 #include "core/net.h"
00034 #include "drivers/rtl8211.h"
00035 #include "debug.h"
00036 
00037 
00038 /**
00039  * @brief RTL8211 Ethernet PHY driver
00040  **/
00041 
00042 const PhyDriver rtl8211PhyDriver =
00043 {
00044    rtl8211Init,
00045    rtl8211Tick,
00046    rtl8211EnableIrq,
00047    rtl8211DisableIrq,
00048    rtl8211EventHandler,
00049 };
00050 
00051 
00052 /**
00053  * @brief RTL8211 PHY transceiver initialization
00054  * @param[in] interface Underlying network interface
00055  * @return Error code
00056  **/
00057 
00058 error_t rtl8211Init(NetInterface *interface)
00059 {
00060    //Debug message
00061    TRACE_INFO("Initializing RTL8211...\r\n");
00062 
00063    //Initialize external interrupt line driver
00064    if(interface->extIntDriver != NULL)
00065       interface->extIntDriver->init();
00066 
00067    //Reset PHY transceiver
00068    rtl8211WritePhyReg(interface, RTL8211_PHY_REG_BMCR, BMCR_RESET);
00069    //Wait for the reset to complete
00070    while(rtl8211ReadPhyReg(interface, RTL8211_PHY_REG_BMCR) & BMCR_RESET);
00071 
00072    //Dump PHY registers for debugging purpose
00073    rtl8211DumpPhyReg(interface);
00074 
00075    //The PHY will generate interrupts when link status changes are detected
00076    rtl8211WritePhyReg(interface, RTL8211_PHY_REG_INER, INER_AN_COMPLETE | INER_LINK_STATUS);
00077 
00078    //Force the TCP/IP stack to poll the link state at startup
00079    interface->phyEvent = TRUE;
00080    //Notify the TCP/IP stack of the event
00081    osSetEvent(&netEvent);
00082 
00083    //Successful initialization
00084    return NO_ERROR;
00085 }
00086 
00087 
00088 /**
00089  * @brief RTL8211 timer handler
00090  * @param[in] interface Underlying network interface
00091  **/
00092 
00093 void rtl8211Tick(NetInterface *interface)
00094 {
00095    uint16_t value;
00096    bool_t linkState;
00097 
00098    //No external interrupt line driver?
00099    if(interface->extIntDriver == NULL)
00100    {
00101       //Read basic status register
00102       value = rtl8211ReadPhyReg(interface, RTL8211_PHY_REG_BMSR);
00103       //Retrieve current link state
00104       linkState = (value & BMSR_LINK_STATUS) ? TRUE : FALSE;
00105 
00106       //Link up event?
00107       if(linkState && !interface->linkState)
00108       {
00109          //Set event flag
00110          interface->phyEvent = TRUE;
00111          //Notify the TCP/IP stack of the event
00112          osSetEvent(&netEvent);
00113       }
00114       //Link down event?
00115       else if(!linkState && interface->linkState)
00116       {
00117          //Set event flag
00118          interface->phyEvent = TRUE;
00119          //Notify the TCP/IP stack of the event
00120          osSetEvent(&netEvent);
00121       }
00122    }
00123 }
00124 
00125 
00126 /**
00127  * @brief Enable interrupts
00128  * @param[in] interface Underlying network interface
00129  **/
00130 
00131 void rtl8211EnableIrq(NetInterface *interface)
00132 {
00133    //Enable PHY transceiver interrupts
00134    if(interface->extIntDriver != NULL)
00135       interface->extIntDriver->enableIrq();
00136 }
00137 
00138 
00139 /**
00140  * @brief Disable interrupts
00141  * @param[in] interface Underlying network interface
00142  **/
00143 
00144 void rtl8211DisableIrq(NetInterface *interface)
00145 {
00146    //Disable PHY transceiver interrupts
00147    if(interface->extIntDriver != NULL)
00148       interface->extIntDriver->disableIrq();
00149 }
00150 
00151 
00152 /**
00153  * @brief RTL8211 event handler
00154  * @param[in] interface Underlying network interface
00155  **/
00156 
00157 void rtl8211EventHandler(NetInterface *interface)
00158 {
00159    uint16_t status;
00160 
00161    //Read status register to acknowledge the interrupt
00162    status = rtl8211ReadPhyReg(interface, RTL8211_PHY_REG_INSR);
00163 
00164    //Link status change?
00165    if(status & (INSR_AN_COMPLETE | INSR_LINK_STATUS))
00166    {
00167       //Any link failure condition is latched in the BMSR register... Reading
00168       //the register twice will always return the actual link status
00169       status = rtl8211ReadPhyReg(interface, RTL8211_PHY_REG_BMSR);
00170       status = rtl8211ReadPhyReg(interface, RTL8211_PHY_REG_BMSR);
00171 
00172       //Link is up?
00173       if(status & BMSR_LINK_STATUS)
00174       {
00175          //Read PHY status register
00176          status = rtl8211ReadPhyReg(interface, RTL8211_PHY_REG_PHYSR);
00177 
00178          //Check current speed
00179          switch(status & PHYSR_SPEED_MASK)
00180          {
00181          //10BASE-T
00182          case PHYSR_SPEED_10:
00183             interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
00184             break;
00185          //100BASE-TX
00186          case PHYSR_SPEED_100:
00187             interface->linkSpeed = NIC_LINK_SPEED_100MBPS;
00188             break;
00189          //1000BASE-T
00190          case PHYSR_SPEED_1000:
00191             interface->linkSpeed = NIC_LINK_SPEED_1GBPS;
00192             break;
00193          //Unknown speed
00194          default:
00195             //Debug message
00196             TRACE_WARNING("Invalid speed\r\n");
00197             break;
00198          }
00199 
00200          //Check current duplex mode
00201          if(status & PHYSR_DUPLEX)
00202             interface->duplexMode = NIC_FULL_DUPLEX_MODE;
00203          else
00204             interface->duplexMode = NIC_HALF_DUPLEX_MODE;
00205 
00206          //Update link state
00207          interface->linkState = TRUE;
00208 
00209          //Adjust MAC configuration parameters for proper operation
00210          interface->nicDriver->updateMacConfig(interface);
00211       }
00212       else
00213       {
00214          //Update link state
00215          interface->linkState = FALSE;
00216       }
00217 
00218       //Process link state change event
00219       nicNotifyLinkChange(interface);
00220    }
00221 }
00222 
00223 
00224 /**
00225  * @brief Write PHY register
00226  * @param[in] interface Underlying network interface
00227  * @param[in] address PHY register address
00228  * @param[in] data Register value
00229  **/
00230 
00231 void rtl8211WritePhyReg(NetInterface *interface, uint8_t address, uint16_t data)
00232 {
00233    uint8_t phyAddr;
00234 
00235    //Get the address of the PHY transceiver
00236    if(interface->phyAddr < 32)
00237       phyAddr = interface->phyAddr;
00238    else
00239       phyAddr = RTL8211_PHY_ADDR;
00240 
00241    //Write the specified PHY register
00242    interface->nicDriver->writePhyReg(phyAddr, address, data);
00243 }
00244 
00245 
00246 /**
00247  * @brief Read PHY register
00248  * @param[in] interface Underlying network interface
00249  * @param[in] address PHY register address
00250  * @return Register value
00251  **/
00252 
00253 uint16_t rtl8211ReadPhyReg(NetInterface *interface, uint8_t address)
00254 {
00255    uint8_t phyAddr;
00256 
00257    //Get the address of the PHY transceiver
00258    if(interface->phyAddr < 32)
00259       phyAddr = interface->phyAddr;
00260    else
00261       phyAddr = RTL8211_PHY_ADDR;
00262 
00263    //Read the specified PHY register
00264    return interface->nicDriver->readPhyReg(phyAddr, address);
00265 }
00266 
00267 
00268 /**
00269  * @brief Dump PHY registers for debugging purpose
00270  * @param[in] interface Underlying network interface
00271  **/
00272 
00273 void rtl8211DumpPhyReg(NetInterface *interface)
00274 {
00275    uint8_t i;
00276 
00277    //Loop through PHY registers
00278    for(i = 0; i < 32; i++)
00279    {
00280       //Display current PHY register
00281       TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i, rtl8211ReadPhyReg(interface, i));
00282    }
00283 
00284    //Terminate with a line feed
00285    TRACE_DEBUG("\r\n");
00286 }
00287