Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ksz8061.c Source File

ksz8061.c

Go to the documentation of this file.
00001 /**
00002  * @file ksz8061.c
00003  * @brief KSZ8061 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/ksz8061.h"
00035 #include "debug.h"
00036 
00037 
00038 /**
00039  * @brief KSZ8061 Ethernet PHY driver
00040  **/
00041 
00042 const PhyDriver ksz8061PhyDriver =
00043 {
00044    ksz8061Init,
00045    ksz8061Tick,
00046    ksz8061EnableIrq,
00047    ksz8061DisableIrq,
00048    ksz8061EventHandler,
00049 };
00050 
00051 
00052 /**
00053  * @brief KSZ8061 PHY transceiver initialization
00054  * @param[in] interface Underlying network interface
00055  * @return Error code
00056  **/
00057 
00058 error_t ksz8061Init(NetInterface *interface)
00059 {
00060    //Debug message
00061    TRACE_INFO("Initializing KSZ8061...\r\n");
00062 
00063    //Initialize external interrupt line driver
00064    if(interface->extIntDriver != NULL)
00065       interface->extIntDriver->init();
00066 
00067    //Reset PHY transceiver
00068    ksz8061WritePhyReg(interface, KSZ8061_PHY_REG_BMCR, BMCR_RESET);
00069    //Wait for the reset to complete
00070    while(ksz8061ReadPhyReg(interface, KSZ8061_PHY_REG_BMCR) & BMCR_RESET);
00071 
00072    //Dump PHY registers for debugging purpose
00073    ksz8061DumpPhyReg(interface);
00074 
00075    //The PHY will generate interrupts when link status changes are detected
00076    ksz8061WritePhyReg(interface, KSZ8061_PHY_REG_ICSR, ICSR_LINK_DOWN_IE | ICSR_LINK_UP_IE);
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 KSZ8061 timer handler
00090  * @param[in] interface Underlying network interface
00091  **/
00092 
00093 void ksz8061Tick(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 = ksz8061ReadPhyReg(interface, KSZ8061_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 ksz8061EnableIrq(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 ksz8061DisableIrq(NetInterface *interface)
00145 {
00146    //Disable PHY transceiver interrupts
00147    if(interface->extIntDriver != NULL)
00148       interface->extIntDriver->disableIrq();
00149 }
00150 
00151 
00152 /**
00153  * @brief KSZ8061 event handler
00154  * @param[in] interface Underlying network interface
00155  **/
00156 
00157 void ksz8061EventHandler(NetInterface *interface)
00158 {
00159    uint16_t value;
00160 
00161    //Read status register to acknowledge the interrupt
00162    value = ksz8061ReadPhyReg(interface, KSZ8061_PHY_REG_ICSR);
00163 
00164    //Link status change?
00165    if(value & (ICSR_LINK_DOWN_IF | ICSR_LINK_UP_IF))
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       value = ksz8061ReadPhyReg(interface, KSZ8061_PHY_REG_BMSR);
00170       value = ksz8061ReadPhyReg(interface, KSZ8061_PHY_REG_BMSR);
00171 
00172       //Link is up?
00173       if(value & BMSR_LINK_STATUS)
00174       {
00175          //Read PHY control register
00176          value = ksz8061ReadPhyReg(interface, KSZ8061_PHY_REG_PHYCON1);
00177 
00178          //Check current operation mode
00179          switch(value & PHYCON1_OP_MODE_MASK)
00180          {
00181          //10BASE-T
00182          case PHYCON1_OP_MODE_10BT:
00183             interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
00184             interface->duplexMode = NIC_HALF_DUPLEX_MODE;
00185             break;
00186          //10BASE-T full-duplex
00187          case PHYCON1_OP_MODE_10BT_FD:
00188             interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
00189             interface->duplexMode = NIC_FULL_DUPLEX_MODE;
00190             break;
00191          //100BASE-TX
00192          case PHYCON1_OP_MODE_100BTX:
00193             interface->linkSpeed = NIC_LINK_SPEED_100MBPS;
00194             interface->duplexMode = NIC_HALF_DUPLEX_MODE;
00195             break;
00196          //100BASE-TX full-duplex
00197          case PHYCON1_OP_MODE_100BTX_FD:
00198             interface->linkSpeed = NIC_LINK_SPEED_100MBPS;
00199             interface->duplexMode = NIC_FULL_DUPLEX_MODE;
00200             break;
00201          //Unknown operation mode
00202          default:
00203             //Debug message
00204             TRACE_WARNING("Invalid Duplex mode\r\n");
00205             break;
00206          }
00207 
00208          //Update link state
00209          interface->linkState = TRUE;
00210 
00211          //Adjust MAC configuration parameters for proper operation
00212          interface->nicDriver->updateMacConfig(interface);
00213       }
00214       else
00215       {
00216          //Update link state
00217          interface->linkState = FALSE;
00218       }
00219 
00220       //Process link state change event
00221       nicNotifyLinkChange(interface);
00222    }
00223 }
00224 
00225 
00226 /**
00227  * @brief Write PHY register
00228  * @param[in] interface Underlying network interface
00229  * @param[in] address PHY register address
00230  * @param[in] data Register value
00231  **/
00232 
00233 void ksz8061WritePhyReg(NetInterface *interface, uint8_t address, uint16_t data)
00234 {
00235    uint8_t phyAddr;
00236 
00237    //Get the address of the PHY transceiver
00238    if(interface->phyAddr < 32)
00239       phyAddr = interface->phyAddr;
00240    else
00241       phyAddr = KSZ8061_PHY_ADDR;
00242 
00243    //Write the specified PHY register
00244    interface->nicDriver->writePhyReg(phyAddr, address, data);
00245 }
00246 
00247 
00248 /**
00249  * @brief Read PHY register
00250  * @param[in] interface Underlying network interface
00251  * @param[in] address PHY register address
00252  * @return Register value
00253  **/
00254 
00255 uint16_t ksz8061ReadPhyReg(NetInterface *interface, uint8_t address)
00256 {
00257    uint8_t phyAddr;
00258 
00259    //Get the address of the PHY transceiver
00260    if(interface->phyAddr < 32)
00261       phyAddr = interface->phyAddr;
00262    else
00263       phyAddr = KSZ8061_PHY_ADDR;
00264 
00265    //Read the specified PHY register
00266    return interface->nicDriver->readPhyReg(phyAddr, address);
00267 }
00268 
00269 
00270 /**
00271  * @brief Dump PHY registers for debugging purpose
00272  * @param[in] interface Underlying network interface
00273  **/
00274 
00275 void ksz8061DumpPhyReg(NetInterface *interface)
00276 {
00277    uint8_t i;
00278 
00279    //Loop through PHY registers
00280    for(i = 0; i < 32; i++)
00281    {
00282       //Display current PHY register
00283       TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i, ksz8061ReadPhyReg(interface, i));
00284    }
00285 
00286    //Terminate with a line feed
00287    TRACE_DEBUG("\r\n");
00288 }
00289