| Line No. | Rev | Author | Line |
|---|---|---|---|
| 1 | 32 | kaklik | /********************************************************************* |
| 2 | * |
||
| 3 | * PHY external API implementation for Microchip TCP/IP Stack |
||
| 4 | * |
||
| 5 | ********************************************************************* |
||
| 6 | * FileName: ETHPIC32ExtPhy.c |
||
| 7 | * Dependencies: |
||
| 8 | * Processor: PIC32 |
||
| 9 | * |
||
| 10 | * Complier: MPLAB C32 |
||
| 11 | * MPLAB IDE |
||
| 12 | * Company: Microchip Technology, Inc. |
||
| 13 | * |
||
| 14 | * Software License Agreement |
||
| 15 | * |
||
| 16 | * Copyright © 2009 Microchip Technology Inc. All rights reserved. |
||
| 17 | * |
||
| 18 | * Microchip licenses the Software for your use with Microchip microcontrollers |
||
| 19 | * and Microchip digital signal controllers pursuant to the terms of the |
||
| 20 | * Non-Exclusive Software License Agreement accompanying this Software. |
||
| 21 | * |
||
| 22 | * SOFTWARE AND DOCUMENTATION ARE PROVIDED AS IS WITHOUT WARRANTY |
||
| 23 | * OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, |
||
| 24 | * ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS |
||
| 25 | * FOR A PARTICULAR PURPOSE. |
||
| 26 | * MICROCHIP AND ITS LICENSORS ASSUME NO RESPONSIBILITY FOR THE ACCURACY, |
||
| 27 | * RELIABILITY OR APPLICATION OF THE SOFTWARE AND DOCUMENTATION. |
||
| 28 | * IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED |
||
| 29 | * UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH |
||
| 30 | * OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT |
||
| 31 | * DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, |
||
| 32 | * SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS |
||
| 33 | * OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, |
||
| 34 | * SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED |
||
| 35 | * TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. |
||
| 36 | * |
||
| 37 | * $Id: $ |
||
| 38 | ********************************************************************/ |
||
| 39 | |||
| 40 | |||
| 41 | #include <plib.h> |
||
| 42 | |||
| 43 | // Compile only for PIC32MX with Ethernet MAC interface (must not have external ENCX24J600, ENC28J60, or ZG2100M hardware defined) |
||
| 44 | #if defined(__PIC32MX__) && defined(_ETH) && !defined(ENC100_INTERFACE_MODE) && !defined(ENC_CS_TRIS) && !defined(ZG_CS_TRIS) |
||
| 45 | |||
| 46 | #include "TCPIP Stack/ETHPIC32ExtPhy.h" |
||
| 47 | |||
| 48 | #include "TCPIP Stack/ETHPIC32ExtPhyRegs.h" |
||
| 49 | |||
| 50 | #include "HardwareProfile.h" |
||
| 51 | |||
| 52 | |||
| 53 | // local definitions |
||
| 54 | // |
||
| 55 | #define PROT_802_3 0x01 // IEEE 802.3 capability |
||
| 56 | #define MAC_COMM_CPBL_MASK (_BMSTAT_BASE10T_HDX_MASK|_BMSTAT_BASE10T_FDX_MASK|_BMSTAT_BASE100TX_HDX_MASK|_BMSTAT_BASE100TX_FDX_MASK) |
||
| 57 | // all comm capabilities our MAC supports |
||
| 58 | |||
| 59 | |||
| 60 | |||
| 61 | // local prototypes |
||
| 62 | // |
||
| 63 | |||
| 64 | static void _PhyInitIo(void); |
||
| 65 | static int _PhyDetectReset(void); |
||
| 66 | |||
| 67 | |||
| 68 | |||
| 69 | // local data |
||
| 70 | // |
||
| 71 | unsigned int _PhyAdd; // address of the PHY we're talking to |
||
| 72 | |||
| 73 | |||
| 74 | |||
| 75 | // local inlined functions |
||
| 76 | // |
||
| 77 | |||
| 78 | static __inline__ eEthLinkStat __attribute__((always_inline)) _Phy2LinkStat(__BMSTATbits_t phyStat) |
||
| 79 | { |
||
| 80 | eEthLinkStat linkStat; |
||
| 81 | linkStat=(phyStat.LINK_STAT)?ETH_LINK_ST_UP:ETH_LINK_ST_DOWN; |
||
| 82 | if(phyStat.REM_FAULT) |
||
| 83 | { |
||
| 84 | linkStat|=ETH_LINK_ST_REMOTE_FAULT; |
||
| 85 | } |
||
| 86 | |||
| 87 | return linkStat; |
||
| 88 | } |
||
| 89 | |||
| 90 | |||
| 91 | |||
| 92 | /**************************************************************************** |
||
| 93 | * interface functions |
||
| 94 | ****************************************************************************/ |
||
| 95 | |||
| 96 | |||
| 97 | |||
| 98 | /**************************************************************************** |
||
| 99 | * Function: EthPhyInit |
||
| 100 | * |
||
| 101 | * PreCondition: - EthInit should have been called. |
||
| 102 | * |
||
| 103 | * Input: oFlags - the requested open flags |
||
| 104 | * cFlags - PHY MII/RMII configuration flags |
||
| 105 | * pResFlags - address to store the initialization result |
||
| 106 | * |
||
| 107 | * Output: ETH_RES_OK for success, |
||
| 108 | * an error code otherwise |
||
| 109 | * |
||
| 110 | * |
||
| 111 | * Side Effects: None |
||
| 112 | * |
||
| 113 | * Overview: This function initializes the PHY communication. |
||
| 114 | * It tries to detect the external PHY, to read the capabilties and find a match |
||
| 115 | * with the requested features. |
||
| 116 | * Then it programs the PHY accordingly. |
||
| 117 | * |
||
| 118 | * Note: None |
||
| 119 | *****************************************************************************/ |
||
| 120 | eEthRes __attribute__((weak)) EthPhyInit(eEthOpenFlags oFlags, eEthPhyCfgFlags cFlags, eEthOpenFlags* pResFlags) |
||
| 121 | { |
||
| 122 | unsigned short ctrlReg; |
||
| 123 | eEthPhyCfgFlags hwFlags, swFlags; |
||
| 124 | unsigned short phyCpbl, openReqs, matchCpbl; |
||
| 125 | eEthRes res; |
||
| 126 | |||
| 127 | // the way the hw is configured |
||
| 128 | hwFlags=(DEVCFG3bits.FMIIEN!=0)?ETH_PHY_CFG_MII:ETH_PHY_CFG_RMII; |
||
| 129 | hwFlags|=(DEVCFG3bits.FETHIO!=0)?ETH_PHY_CFG_DEFAULT:ETH_PHY_CFG_ALTERNATE; |
||
| 130 | |||
| 131 | if(cFlagsÐ_PHY_CFG_AUTO) |
||
| 132 | { |
||
| 133 | cFlags=hwFlags; |
||
| 134 | } |
||
| 135 | else |
||
| 136 | { // some minimal check against the way the hw is configured |
||
| 137 | swFlags=cFlags&(ETH_PHY_CFG_RMII|ETH_PHY_CFG_ALTERNATE); |
||
| 138 | |||
| 139 | if((swFlags ^ hwFlags)!=0) |
||
| 140 | { // hw-sw configuration mismatch MII/RMII, ALT/DEF config |
||
| 141 | return ETH_RES_CFG_ERR; |
||
| 142 | } |
||
| 143 | } |
||
| 144 | |||
| 145 | |||
| 146 | _PhyAdd=EthPhyMIIMAddress(); // get the PHY address |
||
| 147 | |||
| 148 | |||
| 149 | if(oFlags&(ETH_OPEN_PHY_LOOPBACK|ETH_OPEN_MAC_LOOPBACK)) |
||
| 150 | { |
||
| 151 | oFlags&=~ETH_OPEN_AUTO; // no negotiation in loopback mode! |
||
| 152 | } |
||
| 153 | |||
| 154 | if(!(oFlagsÐ_OPEN_AUTO)) |
||
| 155 | { |
||
| 156 | oFlags&=~ETH_OPEN_MDIX_AUTO; // Auto-MDIX has to be in auto negotiation only |
||
| 157 | } |
||
| 158 | |||
| 159 | _PhyInitIo(); // init IO pins |
||
| 160 | |||
| 161 | EthMIIMInit(GetSystemClock(), EthPhyMIIMClock(), oFlags, (cFlagsÐ_PHY_CFG_RMII)!=0); |
||
| 162 | |||
| 163 | |||
| 164 | // try to detect the PHY and reset it |
||
| 165 | if(!_PhyDetectReset()) |
||
| 166 | { // failed to detect the PHY |
||
| 167 | return ETH_RES_DTCT_ERR; |
||
| 168 | } |
||
| 169 | |||
| 170 | // provide some defaults |
||
| 171 | if(!(oFlags&(ETH_OPEN_FDUPLEX|ETH_OPEN_HDUPLEX))) |
||
| 172 | { |
||
| 173 | oFlags|=ETH_OPEN_HDUPLEX; |
||
| 174 | } |
||
| 175 | if(!(oFlags&(ETH_OPEN_100|ETH_OPEN_10))) |
||
| 176 | { |
||
| 177 | oFlags|=ETH_OPEN_10; |
||
| 178 | } |
||
| 179 | |||
| 180 | if(oFlagsÐ_OPEN_AUTO) |
||
| 181 | { // advertise auto negotiation |
||
| 182 | openReqs=_BMSTAT_AN_ABLE_MASK; |
||
| 183 | |||
| 184 | if(oFlagsÐ_OPEN_100) |
||
| 185 | { |
||
| 186 | if(oFlagsÐ_OPEN_FDUPLEX) |
||
| 187 | { |
||
| 188 | openReqs|=_BMSTAT_BASE100TX_FDX_MASK; |
||
| 189 | } |
||
| 190 | if(oFlagsÐ_OPEN_HDUPLEX) |
||
| 191 | { |
||
| 192 | openReqs|=_BMSTAT_BASE100TX_HDX_MASK; |
||
| 193 | } |
||
| 194 | } |
||
| 195 | |||
| 196 | if(oFlagsÐ_OPEN_10) |
||
| 197 | { |
||
| 198 | if(oFlagsÐ_OPEN_FDUPLEX) |
||
| 199 | { |
||
| 200 | openReqs|=_BMSTAT_BASE10T_FDX_MASK; |
||
| 201 | } |
||
| 202 | if(oFlagsÐ_OPEN_HDUPLEX) |
||
| 203 | { |
||
| 204 | openReqs|=_BMSTAT_BASE10T_HDX_MASK; |
||
| 205 | } |
||
| 206 | } |
||
| 207 | } |
||
| 208 | else |
||
| 209 | { // no auto negotiation |
||
| 210 | if(oFlagsÐ_OPEN_100) |
||
| 211 | { |
||
| 212 | openReqs=(oFlagsÐ_OPEN_FDUPLEX)?_BMSTAT_BASE100TX_FDX_MASK:_BMSTAT_BASE100TX_HDX_MASK; |
||
| 213 | } |
||
| 214 | else |
||
| 215 | { |
||
| 216 | openReqs=(oFlagsÐ_OPEN_FDUPLEX)?_BMSTAT_BASE10T_FDX_MASK:_BMSTAT_BASE10T_HDX_MASK; |
||
| 217 | } |
||
| 218 | } |
||
| 219 | |||
| 220 | // try to match the oFlags with the PHY capabilities |
||
| 221 | phyCpbl=EthMIIMReadReg(PHY_REG_BMSTAT, _PhyAdd); |
||
| 222 | matchCpbl=(openReqs&(MAC_COMM_CPBL_MASK|_BMSTAT_AN_ABLE_MASK))&phyCpbl; // common features |
||
| 223 | if(!(matchCpbl&MAC_COMM_CPBL_MASK)) |
||
| 224 | { // no match? |
||
| 225 | return ETH_RES_CPBL_ERR; |
||
| 226 | } |
||
| 227 | |||
| 228 | // we're ok, we can configure the PHY |
||
| 229 | res=EthPhyConfigureMII(cFlags); |
||
| 230 | if(res!=ETH_RES_OK) |
||
| 231 | { |
||
| 232 | return res; |
||
| 233 | } |
||
| 234 | |||
| 235 | res=EthPhyConfigureMdix(oFlags); |
||
| 236 | if(res!=ETH_RES_OK) |
||
| 237 | { |
||
| 238 | return res; |
||
| 239 | } |
||
| 240 | |||
| 241 | if(matchCpbl&_BMSTAT_AN_ABLE_MASK) |
||
| 242 | { // ok, we can perform auto negotiation |
||
| 243 | unsigned short anadReg; |
||
| 244 | |||
| 245 | anadReg=(((matchCpbl>>_BMSTAT_NEGOTIATION_POS)<<_ANAD_NEGOTIATION_POS)&_ANAD_NEGOTIATION_MASK)|PROT_802_3; |
||
| 246 | if(MAC_PAUSE_CPBL_MASK&MAC_PAUSE_TYPE_PAUSE) |
||
| 247 | { |
||
| 248 | anadReg|=_ANAD_PAUSE_MASK; |
||
| 249 | } |
||
| 250 | if(MAC_PAUSE_CPBL_MASK&MAC_PAUSE_TYPE_ASM_DIR) |
||
| 251 | { |
||
| 252 | anadReg|=_ANAD_ASM_DIR_MASK; |
||
| 253 | } |
||
| 254 | |||
| 255 | EthMIIMWriteReg(PHY_REG_ANAD, _PhyAdd, anadReg); // advertise our capabilities |
||
| 256 | |||
| 257 | EthPhyRestartNegotiation(); // restart negotiation and we'll have to wait |
||
| 258 | } |
||
| 259 | else |
||
| 260 | { // ok, just don't use negotiation |
||
| 261 | |||
| 262 | ctrlReg=0; |
||
| 263 | if(matchCpbl&(_BMSTAT_BASE100TX_HDX_MASK|_BMSTAT_BASE100TX_FDX_MASK)) // set 100Mbps request/capability |
||
| 264 | { |
||
| 265 | ctrlReg|=_BMCON_SPEED_MASK; |
||
| 266 | } |
||
| 267 | |||
| 268 | if(matchCpbl&(_BMSTAT_BASE10T_FDX_MASK|_BMSTAT_BASE100TX_FDX_MASK)) |
||
| 269 | { |
||
| 270 | ctrlReg|=_BMCON_DUPLEX_MASK; |
||
| 271 | } |
||
| 272 | |||
| 273 | if(oFlagsÐ_OPEN_PHY_LOOPBACK) |
||
| 274 | { |
||
| 275 | ctrlReg|=_BMCON_LOOPBACK_MASK; |
||
| 276 | } |
||
| 277 | |||
| 278 | EthMIIMWriteReg(PHY_REG_BMCON, _PhyAdd, ctrlReg); // update the configuration |
||
| 279 | } |
||
| 280 | |||
| 281 | |||
| 282 | // now update the open flags |
||
| 283 | // the upper layer needs to know the PHY set-up to further set-up the MAC. |
||
| 284 | |||
| 285 | // clear the capabilities |
||
| 286 | oFlags&=~(ETH_OPEN_AUTO|ETH_OPEN_FDUPLEX|ETH_OPEN_HDUPLEX|ETH_OPEN_100|ETH_OPEN_10); |
||
| 287 | |||
| 288 | if(matchCpbl&_BMSTAT_AN_ABLE_MASK) |
||
| 289 | { |
||
| 290 | oFlags|=ETH_OPEN_AUTO; |
||
| 291 | } |
||
| 292 | if(matchCpbl&(_BMSTAT_BASE100TX_HDX_MASK|_BMSTAT_BASE100TX_FDX_MASK)) // set 100Mbps request/capability |
||
| 293 | { |
||
| 294 | oFlags|=ETH_OPEN_100; |
||
| 295 | } |
||
| 296 | if(matchCpbl&(_BMSTAT_BASE10T_HDX_MASK|_BMSTAT_BASE10T_FDX_MASK)) // set 10Mbps request/capability |
||
| 297 | { |
||
| 298 | oFlags|=ETH_OPEN_10; |
||
| 299 | } |
||
| 300 | if(matchCpbl&(_BMSTAT_BASE10T_FDX_MASK|_BMSTAT_BASE100TX_FDX_MASK)) |
||
| 301 | { |
||
| 302 | oFlags|=ETH_OPEN_FDUPLEX; |
||
| 303 | } |
||
| 304 | if(matchCpbl&(_BMSTAT_BASE10T_HDX_MASK|_BMSTAT_BASE100TX_HDX_MASK)) |
||
| 305 | { |
||
| 306 | oFlags|=ETH_OPEN_HDUPLEX; |
||
| 307 | } |
||
| 308 | |||
| 309 | *pResFlags=oFlags; // upper layer needs to know the PHY set-up to further set-up the MAC. |
||
| 310 | |||
| 311 | return ETH_RES_OK; |
||
| 312 | |||
| 313 | } |
||
| 314 | |||
| 315 | |||
| 316 | /**************************************************************************** |
||
| 317 | * Function: EthPhyRestartNegotiation |
||
| 318 | * |
||
| 319 | * PreCondition: - EthPhyInit should have been called. |
||
| 320 | * - The PHY should have been initialized with proper duplex/speed mode! |
||
| 321 | * |
||
| 322 | * Input: None |
||
| 323 | * |
||
| 324 | * Output: ETH_RES_OK for success, |
||
| 325 | * ETH_RES_NEGOTIATION_UNABLE if the auto-negotiation is not supported. |
||
| 326 | * |
||
| 327 | * Side Effects: None |
||
| 328 | * |
||
| 329 | * Overview: This function restarts the PHY negotiation. |
||
| 330 | * After this restart the link can be reconfigured. |
||
| 331 | * The EthPhyGetNegotiationResults() can be used to see the outcoming result. |
||
| 332 | * |
||
| 333 | * Note: None |
||
| 334 | *****************************************************************************/ |
||
| 335 | eEthRes __attribute__((weak)) EthPhyRestartNegotiation(void) |
||
| 336 | { |
||
| 337 | eEthRes res; |
||
| 338 | __BMSTATbits_t phyCpbl; |
||
| 339 | |||
| 340 | phyCpbl.w=EthMIIMReadReg(PHY_REG_BMSTAT, _PhyAdd); |
||
| 341 | |||
| 342 | if(phyCpbl.AN_ABLE) |
||
| 343 | { // ok, we can perform auto negotiation |
||
| 344 | EthMIIMWriteReg(PHY_REG_BMCON, _PhyAdd, _BMCON_AN_ENABLE_MASK|_BMCON_AN_RESTART_MASK); // restart negotiation and we'll have to wait |
||
| 345 | res=ETH_RES_OK; |
||
| 346 | } |
||
| 347 | else |
||
| 348 | { |
||
| 349 | res=ETH_RES_NEGOTIATION_UNABLE; // no negotiation ability! |
||
| 350 | } |
||
| 351 | |||
| 352 | return res; |
||
| 353 | } |
||
| 354 | |||
| 355 | |||
| 356 | |||
| 357 | /**************************************************************************** |
||
| 358 | * Function: EthPhyNegotiationComplete |
||
| 359 | * |
||
| 360 | * PreCondition: EthPhyInit (and EthPhyRestartNegotiation) should have been called. |
||
| 361 | * |
||
| 362 | * Input: waitComplete - if wait for completion needed |
||
| 363 | * |
||
| 364 | * Output: ETH_RES_OK if negotiation done, |
||
| 365 | * ETH_RES_NEGOTIATION_INACTIVE if no negotiation in progress |
||
| 366 | * ETH_RES_NEGOTIATION_NOT_STARTED if negotiation not started yet (means tmo if waitComplete was requested) |
||
| 367 | * ETH_RES_NEGOTIATION_ACTIVE if negotiation ongoing (means tmo if waitComplete was requested) |
||
| 368 | * |
||
| 369 | * Side Effects: None |
||
| 370 | * |
||
| 371 | * Overview: This function waits for a previously initiated PHY negotiation to complete. |
||
| 372 | * Subsequently, EthPhyGetNegotiationResult() can be called. |
||
| 373 | * |
||
| 374 | * Note: None |
||
| 375 | *****************************************************************************/ |
||
| 376 | eEthRes __attribute__((weak)) EthPhyNegotiationComplete(int waitComplete) |
||
| 377 | { |
||
| 378 | __BMCONbits_t phyBMCon; |
||
| 379 | __BMSTATbits_t phyStat; |
||
| 380 | eEthRes res; |
||
| 381 | |||
| 382 | phyBMCon.w=EthMIIMReadReg(PHY_REG_BMCON, _PhyAdd); |
||
| 383 | if(phyBMCon.AN_ENABLE) |
||
| 384 | { // just protect from an accidental call |
||
| 385 | phyBMCon.w=EthMIIMReadReg(PHY_REG_BMCON, _PhyAdd); |
||
| 386 | phyStat.w=EthMIIMReadReg(PHY_REG_BMSTAT, _PhyAdd); |
||
| 387 | |||
| 388 | if(waitComplete) |
||
| 389 | { |
||
| 390 | unsigned int tStart, tWait; |
||
| 391 | |||
| 392 | if(phyBMCon.AN_RESTART) |
||
| 393 | { // not started yet |
||
| 394 | tWait=(GetSystemClock()/2000)*PHY_NEG_INIT_TMO; |
||
| 395 | tStart=ReadCoreTimer(); |
||
| 396 | do |
||
| 397 | { |
||
| 398 | phyBMCon.w=EthMIIMReadReg(PHY_REG_BMCON, _PhyAdd); |
||
| 399 | }while(phyBMCon.AN_RESTART && (ReadCoreTimer()-tStart)<tWait); // wait auto negotiation start |
||
| 400 | } |
||
| 401 | |||
| 402 | if(!phyBMCon.AN_RESTART) |
||
| 403 | { // ok, started |
||
| 404 | tWait=(GetSystemClock()/2000)*PHY_NEG_DONE_TMO; |
||
| 405 | tStart=ReadCoreTimer(); |
||
| 406 | do |
||
| 407 | { |
||
| 408 | phyStat.w=EthMIIMReadReg(PHY_REG_BMSTAT, _PhyAdd); |
||
| 409 | }while(phyStat.AN_COMPLETE==0 && (ReadCoreTimer()-tStart)<tWait); // wait auto negotiation done |
||
| 410 | |||
| 411 | phyStat.w=EthMIIMReadReg(PHY_REG_BMSTAT, _PhyAdd); |
||
| 412 | } |
||
| 413 | } |
||
| 414 | } |
||
| 415 | |||
| 416 | if(!phyBMCon.AN_ENABLE) |
||
| 417 | { |
||
| 418 | res=ETH_RES_NEGOTIATION_INACTIVE; // no negotiation is taking place! |
||
| 419 | } |
||
| 420 | else if(phyBMCon.AN_RESTART) |
||
| 421 | { |
||
| 422 | res=ETH_RES_NEGOTIATION_NOT_STARTED; // not started yet/tmo |
||
| 423 | } |
||
| 424 | else |
||
| 425 | { |
||
| 426 | res= (phyStat.AN_COMPLETE==0)?ETH_RES_NEGOTIATION_ACTIVE:ETH_RES_OK; // active/tmo/ok |
||
| 427 | } |
||
| 428 | |||
| 429 | return res; |
||
| 430 | } |
||
| 431 | |||
| 432 | |||
| 433 | |||
| 434 | /**************************************************************************** |
||
| 435 | * Function: EthPhyGetNegotiationResult |
||
| 436 | * |
||
| 437 | * PreCondition: EthPhyInit, EthPhyRestartNegotiation and EthPhyNegotiationComplete should have been called. |
||
| 438 | * |
||
| 439 | * Input: pFlags - address to store the negotiation result |
||
| 440 | * pPauseType - address to store the pause type supported by the LP |
||
| 441 | * |
||
| 442 | * Output: the link status after the (completed) negotiation |
||
| 443 | * |
||
| 444 | * Side Effects: None |
||
| 445 | * |
||
| 446 | * Overview: This function returns the result of a previously initiated negotiation. |
||
| 447 | * The result is based on the PHY status!. |
||
| 448 | * |
||
| 449 | * Note: If no negotiation possible/active/failed, most likely the flags are invalid! |
||
| 450 | *****************************************************************************/ |
||
| 451 | eEthLinkStat __attribute__((weak)) EthPhyGetNegotiationResult(eEthOpenFlags* pFlags, eMacPauseType* pPauseType) |
||
| 452 | { |
||
| 453 | eEthLinkStat linkStat; |
||
| 454 | eEthOpenFlags oFlags; |
||
| 455 | __BMSTATbits_t phyStat; |
||
| 456 | __ANEXPbits_t phyExp; |
||
| 457 | __ANLPADbits_t lpAD; |
||
| 458 | __ANADbits_t anadReg; |
||
| 459 | eMacPauseType pauseType; |
||
| 460 | |||
| 461 | |||
| 462 | // should have BMCON.AN_ENABLE==1 |
||
| 463 | // wait for it to finish! |
||
| 464 | |||
| 465 | |||
| 466 | oFlags=0; // don't know the result yet |
||
| 467 | pauseType=MAC_PAUSE_TYPE_NONE; |
||
| 468 | |||
| 469 | phyStat.w=EthMIIMReadReg(PHY_REG_BMSTAT, _PhyAdd); |
||
| 470 | if(phyStat.AN_COMPLETE==0) |
||
| 471 | { |
||
| 472 | linkStat=(ETH_LINK_ST_DOWN|ETH_LINK_ST_NEG_TMO); |
||
| 473 | } |
||
| 474 | else if(!phyStat.LINK_STAT) |
||
| 475 | { |
||
| 476 | linkStat=ETH_LINK_ST_DOWN; |
||
| 477 | } |
||
| 478 | else |
||
| 479 | { // we're up and running |
||
| 480 | int lcl_Pause, lcl_AsmDir, lp_Pause, lp_AsmDir; // pause capabilities, local and LP |
||
| 481 | |||
| 482 | linkStat=ETH_LINK_ST_UP; |
||
| 483 | |||
| 484 | lcl_Pause=(MAC_PAUSE_CPBL_MASK&MAC_PAUSE_TYPE_PAUSE)?1:0; |
||
| 485 | lcl_AsmDir=(MAC_PAUSE_CPBL_MASK&MAC_PAUSE_TYPE_ASM_DIR)?1:0; |
||
| 486 | lp_Pause=lp_AsmDir=0; // in case negotiation fails |
||
| 487 | lpAD.w=_ANAD_BASE10T_MASK; // lowest priority resolution |
||
| 488 | |||
| 489 | phyExp.w=EthMIIMReadReg(PHY_REG_ANEXP, _PhyAdd); |
||
| 490 | if(phyExp.LP_AN_ABLE) |
||
| 491 | { // ok,valid auto negotiation info |
||
| 492 | |||
| 493 | lpAD.w=EthMIIMReadReg(PHY_REG_ANLPAD, _PhyAdd); |
||
| 494 | if(lpAD.REM_FAULT) |
||
| 495 | { |
||
| 496 | linkStat|=ETH_LINK_ST_REMOTE_FAULT; |
||
| 497 | } |
||
| 498 | |||
| 499 | if(lpAD.PAUSE) |
||
| 500 | { |
||
| 501 | linkStat|=ETH_LINK_ST_LP_PAUSE; |
||
| 502 | lp_Pause=1; |
||
| 503 | } |
||
| 504 | if(lpAD.ASM_DIR) |
||
| 505 | { |
||
| 506 | linkStat|=ETH_LINK_ST_LP_ASM_DIR; |
||
| 507 | lp_AsmDir=1; |
||
| 508 | } |
||
| 509 | |||
| 510 | } |
||
| 511 | else |
||
| 512 | { |
||
| 513 | linkStat|=ETH_LINK_ST_LP_NEG_UNABLE; |
||
| 514 | if(phyExp.PDF) |
||
| 515 | { |
||
| 516 | linkStat|=ETH_LINK_ST_PDF; |
||
| 517 | } |
||
| 518 | } |
||
| 519 | |||
| 520 | // set the PHY connection params |
||
| 521 | |||
| 522 | anadReg.w=EthMIIMReadReg(PHY_REG_ANAD, _PhyAdd); // get our advertised capabilities |
||
| 523 | anadReg.w&=lpAD.w; // get the matching ones |
||
| 524 | // get the settings, according to IEEE 802.3 Annex 28B.3 Priority Resolution |
||
| 525 | // Note: we don't support 100BaseT4 ! |
||
| 526 | |||
| 527 | if(anadReg.w&_ANAD_BASE100TX_FDX_MASK) |
||
| 528 | { |
||
| 529 | oFlags=(ETH_OPEN_100|ETH_OPEN_FDUPLEX); |
||
| 530 | } |
||
| 531 | else if(anadReg.w&_ANAD_BASE100TX_MASK) |
||
| 532 | { |
||
| 533 | oFlags=(ETH_OPEN_100|ETH_OPEN_HDUPLEX); |
||
| 534 | } |
||
| 535 | else if(anadReg.w&_ANAD_BASE10T_FDX_MASK) |
||
| 536 | { |
||
| 537 | oFlags=(ETH_OPEN_10|ETH_OPEN_FDUPLEX); |
||
| 538 | } |
||
| 539 | else if(anadReg.w&_ANAD_BASE10T_MASK) |
||
| 540 | { |
||
| 541 | oFlags=(ETH_OPEN_10|ETH_OPEN_HDUPLEX); |
||
| 542 | } |
||
| 543 | else |
||
| 544 | { // this should NOT happen! |
||
| 545 | linkStat|=ETH_LINK_ST_NEG_FATAL_ERR; |
||
| 546 | linkStat&=~ETH_LINK_ST_UP; // make sure we stop...! |
||
| 547 | } |
||
| 548 | |||
| 549 | |||
| 550 | // set the pause type for the MAC |
||
| 551 | // according to IEEE Std 802.3-2002 Tables 28B-2, 28B-3 |
||
| 552 | if(oFlagsÐ_OPEN_FDUPLEX) |
||
| 553 | { // pause type relevant for full duplex only |
||
| 554 | if(lp_Pause & (lcl_Pause|(lcl_AsmDir&lp_AsmDir))) |
||
| 555 | { |
||
| 556 | pauseType=MAC_PAUSE_TYPE_EN_TX; |
||
| 557 | } |
||
| 558 | if(lcl_Pause & (lp_Pause | (lcl_AsmDir&lp_AsmDir))) |
||
| 559 | { |
||
| 560 | pauseType|=MAC_PAUSE_TYPE_EN_RX; |
||
| 561 | } |
||
| 562 | } |
||
| 563 | } |
||
| 564 | |||
| 565 | if(pFlags) |
||
| 566 | { |
||
| 567 | *pFlags=oFlags; |
||
| 568 | } |
||
| 569 | |||
| 570 | if(pPauseType) |
||
| 571 | { |
||
| 572 | *pPauseType=pauseType; |
||
| 573 | } |
||
| 574 | return linkStat; |
||
| 575 | } |
||
| 576 | |||
| 577 | /**************************************************************************** |
||
| 578 | * Function: EthPhyGetLinkStatus |
||
| 579 | * |
||
| 580 | * PreCondition: EthPhyInit should have been called. |
||
| 581 | * |
||
| 582 | * Input: refresh - boolean to specify if double read is needed. |
||
| 583 | * |
||
| 584 | * Output: the current link status |
||
| 585 | * |
||
| 586 | * Side Effects: None |
||
| 587 | * |
||
| 588 | * Overview: This function reads the PHY to get current link status |
||
| 589 | * If refresh is specified then, if the link is down a second read |
||
| 590 | * will be performed to return the current link status. |
||
| 591 | * |
||
| 592 | * Note: None |
||
| 593 | *****************************************************************************/ |
||
| 594 | eEthLinkStat __attribute__((weak)) EthPhyGetLinkStatus(int refresh) |
||
| 595 | { |
||
| 596 | __BMSTATbits_t phyStat; |
||
| 597 | |||
| 598 | // read the link status |
||
| 599 | phyStat.w=EthMIIMReadReg(PHY_REG_BMSTAT, _PhyAdd); |
||
| 600 | if(phyStat.LINK_STAT==0 && refresh) |
||
| 601 | { // link down could be an old condition. re-read |
||
| 602 | phyStat.w=EthMIIMReadReg(PHY_REG_BMSTAT, _PhyAdd); |
||
| 603 | } |
||
| 604 | |||
| 605 | return _Phy2LinkStat(phyStat); |
||
| 606 | } |
||
| 607 | |||
| 608 | |||
| 609 | /**************************************************************************** |
||
| 610 | * Function: EthPhyReset |
||
| 611 | * |
||
| 612 | * PreCondition: EthPhyInit() should have been called |
||
| 613 | * Communication with the PHY already established |
||
| 614 | * |
||
| 615 | * Input: waitComplete - if TRUE the procedure will wait for reset to complete |
||
| 616 | * |
||
| 617 | * Output: TRUE if the reset procedure completed (or completion not required) |
||
| 618 | * FALSE otherwise |
||
| 619 | * |
||
| 620 | * Side Effects: None |
||
| 621 | * |
||
| 622 | * Overview: This function immediately resets the PHY. |
||
| 623 | * It does not wait for the reset procedure to complete |
||
| 624 | * |
||
| 625 | * Note: None |
||
| 626 | *****************************************************************************/ |
||
| 627 | int __attribute__((weak)) EthPhyReset(int waitComplete) |
||
| 628 | { |
||
| 629 | |||
| 630 | EthMIIMWriteReg(PHY_REG_BMCON, _BMCON_RESET_MASK, _PhyAdd); // Soft Reset the PHY |
||
| 631 | |||
| 632 | if(waitComplete) |
||
| 633 | { // wait reset self clear |
||
| 634 | __BMCONbits_t bmcon; |
||
| 635 | unsigned int tStart, tWaitReset; |
||
| 636 | |||
| 637 | tWaitReset=(GetSystemClock()/2000)*PHY_RESET_CLR_TMO; |
||
| 638 | tStart=ReadCoreTimer(); |
||
| 639 | do |
||
| 640 | { |
||
| 641 | bmcon.w=EthMIIMReadReg(PHY_REG_BMCON, _PhyAdd); |
||
| 642 | }while(bmcon.RESET && (ReadCoreTimer()-tStart)<tWaitReset); |
||
| 643 | |||
| 644 | bmcon.w=EthMIIMReadReg(PHY_REG_BMCON, _PhyAdd); |
||
| 645 | if(bmcon.RESET) |
||
| 646 | { // tmo clearing the reset |
||
| 647 | return 0; |
||
| 648 | } |
||
| 649 | } |
||
| 650 | |||
| 651 | return 1; |
||
| 652 | |||
| 653 | } |
||
| 654 | |||
| 655 | |||
| 656 | |||
| 657 | /**************************************************************************** |
||
| 658 | * Function: EthPhyScanLinkStart |
||
| 659 | * |
||
| 660 | * PreCondition: EthPhyInit() should have been called |
||
| 661 | * Communication with the PHY already established |
||
| 662 | * |
||
| 663 | * Input: None |
||
| 664 | * |
||
| 665 | * Output: None |
||
| 666 | * |
||
| 667 | * Side Effects: None |
||
| 668 | * |
||
| 669 | * Overview: This function starts a scan of the PHY link status register. |
||
| 670 | * It is meant as a more efficient way of having access to the current link status |
||
| 671 | * since the normal MIIM frame read operation is pretty lengthy. |
||
| 672 | * |
||
| 673 | * Note: Any PHY register can be subject of a scan. |
||
| 674 | * The application should use the MIIM access functions of the Ethernet plib abd the specific PHY knowledge. |
||
| 675 | *****************************************************************************/ |
||
| 676 | void __attribute__((weak)) EthPhyScanLinkStart(void) |
||
| 677 | { |
||
| 678 | EthMIIMScanStart(PHY_REG_BMSTAT, _PhyAdd); |
||
| 679 | } |
||
| 680 | |||
| 681 | /**************************************************************************** |
||
| 682 | * Function: EthPhyScanLinkRead |
||
| 683 | * |
||
| 684 | * PreCondition: EthPhyInit() should have been called |
||
| 685 | * Communication with the PHY already established |
||
| 686 | * A PHY scan operation should have been started. |
||
| 687 | * |
||
| 688 | * Input: None |
||
| 689 | * |
||
| 690 | * Output: the current link status as being updated by the current scan in progress |
||
| 691 | * |
||
| 692 | * Side Effects: None |
||
| 693 | * |
||
| 694 | * Overview: This function returns the current result of a scan operation. |
||
| 695 | * The last updated value is returned. |
||
| 696 | * There's no way of knowing when effectively this last update occurred. |
||
| 697 | * |
||
| 698 | * Note: None |
||
| 699 | *****************************************************************************/ |
||
| 700 | eEthLinkStat __attribute__((weak)) EthPhyScanLinkRead(void) |
||
| 701 | { |
||
| 702 | __BMSTATbits_t phyStat; |
||
| 703 | |||
| 704 | phyStat.w=EthMIIMScanRead(); |
||
| 705 | |||
| 706 | return _Phy2LinkStat(phyStat); |
||
| 707 | } |
||
| 708 | |||
| 709 | |||
| 710 | /**************************************************************************** |
||
| 711 | * Function: EthPhyScanLinkStop |
||
| 712 | * |
||
| 713 | * PreCondition: EthPhyInit() should have been called |
||
| 714 | * Communication with the PHY already established |
||
| 715 | * A PHY scan operation should have been started. |
||
| 716 | * |
||
| 717 | * Input: None |
||
| 718 | * |
||
| 719 | * Output: None |
||
| 720 | * |
||
| 721 | * Side Effects: None |
||
| 722 | * |
||
| 723 | * Overview: This function stops a previously started PHY scan. |
||
| 724 | * |
||
| 725 | * Note: The scan operation shouldn't interfere with normal read operations. |
||
| 726 | * Therefore the scan operation should be stopped before initiating another |
||
| 727 | * normal MIIM transaction |
||
| 728 | *****************************************************************************/ |
||
| 729 | void __attribute__((weak)) EthPhyScanLinkStop(void) |
||
| 730 | { |
||
| 731 | EthMIIMScanStop(); |
||
| 732 | } |
||
| 733 | |||
| 734 | |||
| 735 | |||
| 736 | |||
| 737 | /**************************************************************************** |
||
| 738 | * local functions |
||
| 739 | ****************************************************************************/ |
||
| 740 | |||
| 741 | |||
| 742 | /**************************************************************************** |
||
| 743 | * Function: _PhyInitIo |
||
| 744 | * |
||
| 745 | * PreCondition: None |
||
| 746 | * |
||
| 747 | * Input: None |
||
| 748 | * |
||
| 749 | * Output: None |
||
| 750 | * |
||
| 751 | * Side Effects: None |
||
| 752 | * |
||
| 753 | * Overview: Helper to properly set the Eth i/o pins to digital pins. |
||
| 754 | * |
||
| 755 | * Note: Even when the Eth device is turned on the analog shared pins have to be configured. |
||
| 756 | *****************************************************************************/ |
||
| 757 | static void _PhyInitIo(void) |
||
| 758 | { |
||
| 759 | __DEVCFG3bits_t bcfg3; |
||
| 760 | |||
| 761 | bcfg3=DEVCFG3bits; |
||
| 762 | if(bcfg3.FETHIO) |
||
| 763 | { // default setting, both RMII and MII |
||
| 764 | PORTSetPinsDigitalOut(_ETH_MDC_PORT, _ETH_MDC_BIT); |
||
| 765 | PORTSetPinsDigitalIn(_ETH_MDIO_PORT, _ETH_MDIO_BIT); |
||
| 766 | |||
| 767 | PORTSetPinsDigitalOut(_ETH_TXEN_PORT, _ETH_TXEN_BIT); |
||
| 768 | PORTSetPinsDigitalOut(_ETH_TXD0_PORT, _ETH_TXD0_BIT); |
||
| 769 | PORTSetPinsDigitalOut(_ETH_TXD1_PORT, _ETH_TXD1_BIT); |
||
| 770 | |||
| 771 | |||
| 772 | PORTSetPinsDigitalIn(_ETH_RXCLK_PORT, _ETH_RXCLK_BIT); |
||
| 773 | PORTSetPinsDigitalIn(_ETH_RXDV_PORT, _ETH_RXDV_BIT); |
||
| 774 | PORTSetPinsDigitalIn(_ETH_RXD0_PORT, _ETH_RXD0_BIT); |
||
| 775 | PORTSetPinsDigitalIn(_ETH_RXD1_PORT, _ETH_RXD1_BIT); |
||
| 776 | PORTSetPinsDigitalIn(_ETH_RXERR_PORT, _ETH_RXERR_BIT); |
||
| 777 | |||
| 778 | |||
| 779 | if(bcfg3.FMIIEN) |
||
| 780 | { // just MII |
||
| 781 | PORTSetPinsDigitalIn(_ETH_TXCLK_PORT, _ETH_TXCLK_BIT); |
||
| 782 | PORTSetPinsDigitalOut(_ETH_TXD2_PORT, _ETH_TXD2_BIT); |
||
| 783 | PORTSetPinsDigitalOut(_ETH_TXD3_PORT, _ETH_TXD3_BIT); |
||
| 784 | PORTSetPinsDigitalOut(_ETH_TXERR_PORT, _ETH_TXERR_BIT); |
||
| 785 | |||
| 786 | PORTSetPinsDigitalIn(_ETH_RXD2_PORT, _ETH_RXD2_BIT); |
||
| 787 | PORTSetPinsDigitalIn(_ETH_RXD3_PORT, _ETH_RXD3_BIT); |
||
| 788 | PORTSetPinsDigitalIn(_ETH_CRS_PORT, _ETH_CRS_BIT); |
||
| 789 | PORTSetPinsDigitalIn(_ETH_COL_PORT, _ETH_COL_BIT); |
||
| 790 | } |
||
| 791 | } |
||
| 792 | else |
||
| 793 | { // alternate setting, both RMII and MII |
||
| 794 | PORTSetPinsDigitalOut(_ETH_ALT_MDC_PORT, _ETH_ALT_MDC_BIT); |
||
| 795 | PORTSetPinsDigitalIn(_ETH_ALT_MDIO_PORT, _ETH_ALT_MDIO_BIT); |
||
| 796 | |||
| 797 | PORTSetPinsDigitalOut(_ETH_ALT_TXEN_PORT, _ETH_ALT_TXEN_BIT); |
||
| 798 | PORTSetPinsDigitalOut(_ETH_ALT_TXD0_PORT, _ETH_ALT_TXD0_BIT); |
||
| 799 | PORTSetPinsDigitalOut(_ETH_ALT_TXD1_PORT, _ETH_ALT_TXD1_BIT); |
||
| 800 | |||
| 801 | |||
| 802 | PORTSetPinsDigitalIn(_ETH_ALT_RXCLK_PORT, _ETH_ALT_RXCLK_BIT); |
||
| 803 | PORTSetPinsDigitalIn(_ETH_ALT_RXDV_PORT, _ETH_ALT_RXDV_BIT); |
||
| 804 | PORTSetPinsDigitalIn(_ETH_ALT_RXD0_PORT, _ETH_ALT_RXD0_BIT); |
||
| 805 | PORTSetPinsDigitalIn(_ETH_ALT_RXD1_PORT, _ETH_ALT_RXD1_BIT); |
||
| 806 | PORTSetPinsDigitalIn(_ETH_ALT_RXERR_PORT, _ETH_ALT_RXERR_BIT); |
||
| 807 | |||
| 808 | |||
| 809 | if(bcfg3.FMIIEN) |
||
| 810 | { // just MII |
||
| 811 | PORTSetPinsDigitalIn(_ETH_ALT_TXCLK_PORT, _ETH_ALT_TXCLK_BIT); |
||
| 812 | PORTSetPinsDigitalOut(_ETH_ALT_TXD2_PORT, _ETH_ALT_TXD2_BIT); |
||
| 813 | PORTSetPinsDigitalOut(_ETH_ALT_TXD3_PORT, _ETH_ALT_TXD3_BIT); |
||
| 814 | PORTSetPinsDigitalOut(_ETH_ALT_TXERR_PORT, _ETH_ALT_TXERR_BIT); |
||
| 815 | |||
| 816 | PORTSetPinsDigitalIn(_ETH_ALT_RXD2_PORT, _ETH_ALT_RXD2_BIT); |
||
| 817 | PORTSetPinsDigitalIn(_ETH_ALT_RXD3_PORT, _ETH_ALT_RXD3_BIT); |
||
| 818 | PORTSetPinsDigitalIn(_ETH_ALT_CRS_PORT, _ETH_ALT_CRS_BIT); |
||
| 819 | PORTSetPinsDigitalIn(_ETH_ALT_COL_PORT, _ETH_ALT_COL_BIT); |
||
| 820 | } |
||
| 821 | |||
| 822 | } |
||
| 823 | } |
||
| 824 | |||
| 825 | |||
| 826 | /**************************************************************************** |
||
| 827 | * Function: _PhyDetectReset |
||
| 828 | * |
||
| 829 | * PreCondition: EthMIIMInit() should have been called |
||
| 830 | * |
||
| 831 | * Input: None |
||
| 832 | * |
||
| 833 | * Output: TRUE if the detection and the reset of the PHY succeeded, |
||
| 834 | * FALSE if no PHY detected |
||
| 835 | * |
||
| 836 | * Side Effects: None |
||
| 837 | * |
||
| 838 | * Overview: This function detects and resets the PHY. |
||
| 839 | * |
||
| 840 | * Note: Needs the system running frequency to for the PHY detection |
||
| 841 | *****************************************************************************/ |
||
| 842 | static int _PhyDetectReset(void) |
||
| 843 | { |
||
| 844 | __BMCONbits_t bmcon; |
||
| 845 | unsigned int tStart, tWaitReset; |
||
| 846 | |||
| 847 | bmcon.w=EthMIIMReadReg(PHY_REG_BMCON, _PhyAdd); // read the BMCON register |
||
| 848 | |||
| 849 | if(bmcon.RESET) |
||
| 850 | { // that is already suspicios...but give it a chance to clear itself |
||
| 851 | tWaitReset=(GetSystemClock()/2000)*PHY_RESET_CLR_TMO; |
||
| 852 | tStart=ReadCoreTimer(); |
||
| 853 | do |
||
| 854 | { |
||
| 855 | bmcon.w=EthMIIMReadReg(PHY_REG_BMCON, _PhyAdd); |
||
| 856 | }while(bmcon.RESET && (ReadCoreTimer()-tStart)<tWaitReset); // wait reset self clear |
||
| 857 | |||
| 858 | bmcon.w=EthMIIMReadReg(PHY_REG_BMCON, _PhyAdd); |
||
| 859 | if(bmcon.RESET) |
||
| 860 | { // tmo clearing the reset |
||
| 861 | return 0; |
||
| 862 | } |
||
| 863 | } |
||
| 864 | |||
| 865 | // ok, reset bit is low |
||
| 866 | // try to see if we can write smth to the PHY |
||
| 867 | // we use Loopback and Isolate bits |
||
| 868 | EthMIIMWriteReg(PHY_REG_BMCON, _PhyAdd, _BMCON_LOOPBACK_MASK|_BMCON_ISOLATE_MASK); // write control bits |
||
| 869 | bmcon.w=EthMIIMReadReg(PHY_REG_BMCON, _PhyAdd); // read back |
||
| 870 | if(bmcon.LOOPBACK==0 || bmcon.ISOLATE==0) |
||
| 871 | { // failed to set |
||
| 872 | return 0; |
||
| 873 | } |
||
| 874 | bmcon.w^=_BMCON_LOOPBACK_MASK|_BMCON_ISOLATE_MASK; |
||
| 875 | EthMIIMWriteReg(PHY_REG_BMCON, _PhyAdd, bmcon.w); // clear bits and write |
||
| 876 | bmcon.w=EthMIIMReadReg(PHY_REG_BMCON, _PhyAdd); // read back |
||
| 877 | if(bmcon.LOOPBACK || bmcon.ISOLATE) |
||
| 878 | { // failed to clear |
||
| 879 | return 0; |
||
| 880 | } |
||
| 881 | |||
| 882 | // everything seems to be fine |
||
| 883 | // |
||
| 884 | return EthPhyReset(1); |
||
| 885 | } |
||
| 886 | |||
| 887 | |||
| 888 | #endif // defined(__PIC32MX__) && defined(_ETH) // ETHC present |
||
| 889 |
Powered by WebSVN v2.8.3