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