Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers dm9161.c Source File

dm9161.c

Go to the documentation of this file.
00001 /**
00002  * @file dm9161.c
00003  * @brief DM9161 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/dm9161.h"
00035 #include "debug.h"
00036 
00037 
00038 /**
00039  * @brief DM9161 Ethernet PHY driver
00040  **/
00041 
00042 const PhyDriver dm9161PhyDriver =
00043 {
00044    dm9161Init,
00045    dm9161Tick,
00046    dm9161EnableIrq,
00047    dm9161DisableIrq,
00048    dm9161EventHandler,
00049 };
00050 
00051 
00052 /**
00053  * @brief DM9161 PHY transceiver initialization
00054  * @param[in] interface Underlying network interface
00055  * @return Error code
00056  **/
00057 
00058 error_t dm9161Init(NetInterface *interface)
00059 {
00060    volatile uint32_t status;
00061 
00062    //Debug message
00063    TRACE_INFO("Initializing DM9161...\r\n");
00064 
00065    //Initialize external interrupt line driver
00066    if(interface->extIntDriver != NULL)
00067       interface->extIntDriver->init();
00068 
00069    //Reset PHY transceiver
00070    dm9161WritePhyReg(interface, DM9161_PHY_REG_BMCR, BMCR_RESET);
00071    //Wait for the reset to complete
00072    while(dm9161ReadPhyReg(interface, DM9161_PHY_REG_BMCR) & BMCR_RESET);
00073 
00074    //Dump PHY registers for debugging purpose
00075    dm9161DumpPhyReg(interface);
00076 
00077    //The PHY will generate interrupts when link status changes are detected
00078    dm9161WritePhyReg(interface, DM9161_PHY_REG_MDINTR, ~(MDINTR_LINK_MASK | MDINTR_INTR_MASK));
00079 
00080    //Force the TCP/IP stack to poll the link state at startup
00081    interface->phyEvent = TRUE;
00082    //Notify the TCP/IP stack of the event
00083    osSetEvent(&netEvent);
00084 
00085    //Successful initialization
00086    return NO_ERROR;
00087 }
00088 
00089 
00090 /**
00091  * @brief DM9161 timer handler
00092  * @param[in] interface Underlying network interface
00093  **/
00094 
00095 void dm9161Tick(NetInterface *interface)
00096 {
00097    uint16_t value;
00098    bool_t linkState;
00099 
00100    //No external interrupt line driver?
00101    if(interface->extIntDriver == NULL)
00102    {
00103       //Read basic status register
00104       value = dm9161ReadPhyReg(interface, DM9161_PHY_REG_BMSR);
00105       //Retrieve current link state
00106       linkState = (value & BMSR_LINK_STATUS) ? TRUE : FALSE;
00107 
00108       //Link up event?
00109       if(linkState && !interface->linkState)
00110       {
00111          //Set event flag
00112          interface->phyEvent = TRUE;
00113          //Notify the TCP/IP stack of the event
00114          osSetEvent(&netEvent);
00115       }
00116       //Link down event?
00117       else if(!linkState && interface->linkState)
00118       {
00119          //Set event flag
00120          interface->phyEvent = TRUE;
00121          //Notify the TCP/IP stack of the event
00122          osSetEvent(&netEvent);
00123       }
00124    }
00125 }
00126 
00127 
00128 /**
00129  * @brief Enable interrupts
00130  * @param[in] interface Underlying network interface
00131  **/
00132 
00133 void dm9161EnableIrq(NetInterface *interface)
00134 {
00135    //Enable PHY transceiver interrupts
00136    if(interface->extIntDriver != NULL)
00137       interface->extIntDriver->enableIrq();
00138 }
00139 
00140 
00141 /**
00142  * @brief Disable interrupts
00143  * @param[in] interface Underlying network interface
00144  **/
00145 
00146 void dm9161DisableIrq(NetInterface *interface)
00147 {
00148    //Disable PHY transceiver interrupts
00149    if(interface->extIntDriver != NULL)
00150       interface->extIntDriver->disableIrq();
00151 }
00152 
00153 
00154 /**
00155  * @brief DM9161 event handler
00156  * @param[in] interface Underlying network interface
00157  **/
00158 
00159 void dm9161EventHandler(NetInterface *interface)
00160 {
00161    uint16_t value;
00162    bool_t end;
00163 
00164    //Read status register to acknowledge the interrupt
00165    value = dm9161ReadPhyReg(interface, DM9161_PHY_REG_MDINTR);
00166 
00167    //Link status change?
00168    if(value & MDINTR_LINK_CHANGE)
00169    {
00170       //Any link failure condition is latched in the BMSR register... Reading
00171       //the register twice will always return the actual link status
00172       value = dm9161ReadPhyReg(interface, DM9161_PHY_REG_BMSR);
00173       value = dm9161ReadPhyReg(interface, DM9161_PHY_REG_BMSR);
00174 
00175       //Link is up?
00176       if(value & BMSR_LINK_STATUS)
00177       {
00178          //Wait for the auto-negotiation to complete
00179          do
00180          {
00181             //Read DSCSR register
00182             value = dm9161ReadPhyReg(interface, DM9161_PHY_REG_DSCSR);
00183 
00184             //Check current state
00185             switch(value & DSCSR_ANMB_MASK)
00186             {
00187             //Auto-negotiation is still in progress?
00188             case DSCSR_ANMB_ABILITY_MATCH:
00189             case DSCSR_ANMB_ACK_MATCH:
00190             case DSCSR_ANMB_CONSIST_MATCH:
00191             case DSCSR_ANMB_SIGNAL_LINK_READY:
00192                end = FALSE;
00193                break;
00194             //Auto-negotiation is complete?
00195             default:
00196                end = TRUE;
00197                break;
00198             }
00199 
00200             //Check loop condition variable
00201          } while(!end);
00202 
00203          //Read DSCSR register
00204          value = dm9161ReadPhyReg(interface, DM9161_PHY_REG_DSCSR);
00205 
00206          //Check current operation mode
00207          if(value & DSCSR_10HDX)
00208          {
00209             //10BASE-T half-duplex
00210             interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
00211             interface->duplexMode = NIC_HALF_DUPLEX_MODE;
00212          }
00213          else if(value & DSCSR_10FDX)
00214          {
00215             //10BASE-T full-duplex
00216             interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
00217             interface->duplexMode = NIC_FULL_DUPLEX_MODE;
00218          }
00219          else if(value & DSCSR_100HDX)
00220          {
00221             //100BASE-TX half-duplex
00222             interface->linkSpeed = NIC_LINK_SPEED_100MBPS;
00223             interface->duplexMode = NIC_HALF_DUPLEX_MODE;
00224          }
00225          else if(value & DSCSR_100FDX)
00226          {
00227             //100BASE-TX full-duplex
00228             interface->linkSpeed = NIC_LINK_SPEED_100MBPS;
00229             interface->duplexMode = NIC_FULL_DUPLEX_MODE;
00230          }
00231          else
00232          {
00233             //Debug message
00234             TRACE_WARNING("Invalid Duplex mode\r\n");
00235          }
00236 
00237          //Update link state
00238          interface->linkState = TRUE;
00239 
00240          //Adjust MAC configuration parameters for proper operation
00241          interface->nicDriver->updateMacConfig(interface);
00242       }
00243       else
00244       {
00245          //Update link state
00246          interface->linkState = FALSE;
00247       }
00248 
00249       //Process link state change event
00250       nicNotifyLinkChange(interface);
00251    }
00252 }
00253 
00254 
00255 /**
00256  * @brief Write PHY register
00257  * @param[in] interface Underlying network interface
00258  * @param[in] address PHY register address
00259  * @param[in] data Register value
00260  **/
00261 
00262 void dm9161WritePhyReg(NetInterface *interface, uint8_t address, uint16_t data)
00263 {
00264    uint8_t phyAddr;
00265 
00266    //Get the address of the PHY transceiver
00267    if(interface->phyAddr < 32)
00268       phyAddr = interface->phyAddr;
00269    else
00270       phyAddr = DM9161_PHY_ADDR;
00271 
00272    //Write the specified PHY register
00273    interface->nicDriver->writePhyReg(phyAddr, address, data);
00274 }
00275 
00276 
00277 /**
00278  * @brief Read PHY register
00279  * @param[in] interface Underlying network interface
00280  * @param[in] address PHY register address
00281  * @return Register value
00282  **/
00283 
00284 uint16_t dm9161ReadPhyReg(NetInterface *interface, uint8_t address)
00285 {
00286    uint8_t phyAddr;
00287 
00288    //Get the address of the PHY transceiver
00289    if(interface->phyAddr < 32)
00290       phyAddr = interface->phyAddr;
00291    else
00292       phyAddr = DM9161_PHY_ADDR;
00293 
00294    //Read the specified PHY register
00295    return interface->nicDriver->readPhyReg(phyAddr, address);
00296 }
00297 
00298 
00299 /**
00300  * @brief Dump PHY registers for debugging purpose
00301  * @param[in] interface Underlying network interface
00302  **/
00303 
00304 void dm9161DumpPhyReg(NetInterface *interface)
00305 {
00306    uint8_t i;
00307 
00308    //Loop through PHY registers
00309    for(i = 0; i < 32; i++)
00310    {
00311       //Display current PHY register
00312       TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i, dm9161ReadPhyReg(interface, i));
00313    }
00314 
00315    //Terminate with a line feed
00316    TRACE_DEBUG("\r\n");
00317 }
00318