4 * @author Intel Corporation
7 * @brief MII control functions
13 * IXP400 SW Release version 2.0
15 * -- Copyright Notice --
18 * Copyright 2001-2005, Intel Corporation.
19 * All rights reserved.
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
25 * 1. Redistributions of source code must retain the above copyright
26 * notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
30 * 3. Neither the name of the Intel Corporation nor the names of its contributors
31 * may be used to endorse or promote products derived from this software
32 * without specific prior written permission.
35 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
36 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
39 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * -- End of Copyright Notice --
54 #include "IxEthMii_p.h"
57 #include "IxOsPrintf.h"
60 /* Array to store the phy IDs of the discovered phys */
61 PRIVATE UINT32 ixEthMiiPhyId
[IXP425_ETH_ACC_MII_MAX_ADDR
];
63 /*********************************************************
65 * Scan for PHYs on the MII bus. This function returns
66 * an array of booleans, one for each PHY address.
67 * If a PHY is found at a particular address, the
68 * corresponding entry in the array is set to TRUE.
73 ixEthMiiPhyScan(BOOL phyPresent
[], UINT32 maxPhyCount
)
76 UINT16 regval
, regvalId1
, regvalId2
;
78 /*Search for PHYs on the MII*/
79 /*Search for existant phys on the MDIO bus*/
81 if ((phyPresent
== NULL
) ||
82 (maxPhyCount
> IXP425_ETH_ACC_MII_MAX_ADDR
))
89 i
<IXP425_ETH_ACC_MII_MAX_ADDR
;
92 phyPresent
[i
] = FALSE
;
95 /* iterate through the PHY addresses */
97 maxPhyCount
> 0 && i
<IXP425_ETH_ACC_MII_MAX_ADDR
;
100 ixEthMiiPhyId
[i
] = IX_ETH_MII_INVALID_PHY_ID
;
101 if(ixEthAccMiiReadRtn(i
,
103 ®val
) == IX_ETH_ACC_SUCCESS
)
105 if((regval
& 0xffff) != 0xffff)
108 /*Need to read the register twice here to flush PHY*/
109 ixEthAccMiiReadRtn(i
, IX_ETH_MII_PHY_ID1_REG
, ®valId1
);
110 ixEthAccMiiReadRtn(i
, IX_ETH_MII_PHY_ID1_REG
, ®valId1
);
111 ixEthAccMiiReadRtn(i
, IX_ETH_MII_PHY_ID2_REG
, ®valId2
);
112 ixEthMiiPhyId
[i
] = (regvalId1
<< IX_ETH_MII_REG_SHL
) | regvalId2
;
113 if ((ixEthMiiPhyId
[i
] == IX_ETH_MII_KS8995_PHY_ID
)
114 || (ixEthMiiPhyId
[i
] == IX_ETH_MII_LXT971_PHY_ID
)
115 || (ixEthMiiPhyId
[i
] == IX_ETH_MII_LXT972_PHY_ID
)
116 || (ixEthMiiPhyId
[i
] == IX_ETH_MII_LXT973_PHY_ID
)
117 || (ixEthMiiPhyId
[i
] == IX_ETH_MII_LXT973A3_PHY_ID
)
118 || (ixEthMiiPhyId
[i
] == IX_ETH_MII_LXT9785_PHY_ID
)
122 phyPresent
[i
] = TRUE
;
123 } /* end of if(ixEthMiiPhyId) */
126 if (ixEthMiiPhyId
[i
] != IX_ETH_MII_INVALID_PHY_ID
)
128 /* unsupported phy */
129 ixOsalLog (IX_OSAL_LOG_LVL_ERROR
,
130 IX_OSAL_LOG_DEV_STDOUT
,
131 "ixEthMiiPhyScan : unexpected Mii PHY ID %8.8x\n",
132 ixEthMiiPhyId
[i
], 2, 3, 4, 5, 6);
133 ixEthMiiPhyId
[i
] = IX_ETH_MII_UNKNOWN_PHY_ID
;
134 phyPresent
[i
] = TRUE
;
143 /************************************************************
145 * Configure the PHY at the specified address
149 ixEthMiiPhyConfig(UINT32 phyAddr
,
156 /* parameter check */
157 if ((phyAddr
< IXP425_ETH_ACC_MII_MAX_ADDR
) &&
158 (ixEthMiiPhyId
[phyAddr
] != IX_ETH_MII_INVALID_PHY_ID
))
161 * set the control register
165 regval
|= IX_ETH_MII_CR_AUTO_EN
| IX_ETH_MII_CR_RESTART
;
171 regval
|= IX_ETH_MII_CR_100
;
175 regval
|= IX_ETH_MII_CR_FDX
;
177 } /* end of if-else() */
178 if (ixEthAccMiiWriteRtn(phyAddr
,
180 regval
) == IX_ETH_ACC_SUCCESS
)
184 } /* end of if(phyAddr) */
188 /******************************************************************
190 * Enable the PHY Loopback at the specified address
193 ixEthMiiPhyLoopbackEnable (UINT32 phyAddr
)
197 if ((phyAddr
< IXP425_ETH_ACC_MII_MAX_ADDR
) &&
198 (IX_ETH_MII_INVALID_PHY_ID
!= ixEthMiiPhyId
[phyAddr
]))
200 /* read/write the control register */
201 if(ixEthAccMiiReadRtn (phyAddr
,
204 == IX_ETH_ACC_SUCCESS
)
206 if(ixEthAccMiiWriteRtn (phyAddr
,
208 regval
| IX_ETH_MII_CR_LOOPBACK
)
209 == IX_ETH_ACC_SUCCESS
)
218 /******************************************************************
220 * Disable the PHY Loopback at the specified address
223 ixEthMiiPhyLoopbackDisable (UINT32 phyAddr
)
227 if ((phyAddr
< IXP425_ETH_ACC_MII_MAX_ADDR
) &&
228 (IX_ETH_MII_INVALID_PHY_ID
!= ixEthMiiPhyId
[phyAddr
]))
230 /* read/write the control register */
231 if(ixEthAccMiiReadRtn (phyAddr
,
234 == IX_ETH_ACC_SUCCESS
)
236 if(ixEthAccMiiWriteRtn (phyAddr
,
238 regval
& (~IX_ETH_MII_CR_LOOPBACK
))
239 == IX_ETH_ACC_SUCCESS
)
248 /******************************************************************
250 * Reset the PHY at the specified address
253 ixEthMiiPhyReset(UINT32 phyAddr
)
258 if ((phyAddr
< IXP425_ETH_ACC_MII_MAX_ADDR
) &&
259 (ixEthMiiPhyId
[phyAddr
] != IX_ETH_MII_INVALID_PHY_ID
))
261 if ((ixEthMiiPhyId
[phyAddr
] == IX_ETH_MII_LXT971_PHY_ID
) ||
262 (ixEthMiiPhyId
[phyAddr
] == IX_ETH_MII_LXT972_PHY_ID
) ||
263 (ixEthMiiPhyId
[phyAddr
] == IX_ETH_MII_LXT973_PHY_ID
) ||
264 (ixEthMiiPhyId
[phyAddr
] == IX_ETH_MII_LXT973A3_PHY_ID
) ||
265 (ixEthMiiPhyId
[phyAddr
] == IX_ETH_MII_LXT9785_PHY_ID
)
268 /* use the control register to reset the phy */
269 ixEthAccMiiWriteRtn(phyAddr
,
271 IX_ETH_MII_CR_RESET
);
273 /* poll until the reset bit is cleared */
277 ixOsalSleep (IX_ETH_MII_RESET_POLL_MS
);
279 /* read the control register and check for timeout */
280 ixEthAccMiiReadRtn(phyAddr
,
283 if ((regval
& IX_ETH_MII_CR_RESET
) == 0)
285 /* timeout bit is self-cleared */
288 timeout
+= IX_ETH_MII_RESET_POLL_MS
;
290 while (timeout
< IX_ETH_MII_RESET_DELAY_MS
);
292 /* check for timeout */
293 if (timeout
>= IX_ETH_MII_RESET_DELAY_MS
)
295 ixEthAccMiiWriteRtn(phyAddr
, IX_ETH_MII_CTRL_REG
,
296 IX_ETH_MII_CR_NORM_EN
);
301 } /* end of if(ixEthMiiPhyId) */
302 else if (ixEthMiiPhyId
[phyAddr
] == IX_ETH_MII_KS8995_PHY_ID
)
304 /* reset bit is reserved, just reset the control register */
305 ixEthAccMiiWriteRtn(phyAddr
, IX_ETH_MII_CTRL_REG
,
306 IX_ETH_MII_CR_NORM_EN
);
311 /* unknown PHY, set the control register reset bit,
312 * wait 2 s. and clear the control register.
314 ixEthAccMiiWriteRtn(phyAddr
, IX_ETH_MII_CTRL_REG
,
315 IX_ETH_MII_CR_RESET
);
317 ixOsalSleep (IX_ETH_MII_RESET_DELAY_MS
);
319 ixEthAccMiiWriteRtn(phyAddr
, IX_ETH_MII_CTRL_REG
,
320 IX_ETH_MII_CR_NORM_EN
);
322 } /* end of if-else(ixEthMiiPhyId) */
323 } /* end of if(phyAddr) */
327 /*****************************************************************
329 * Link state query functions
333 ixEthMiiLinkStatus(UINT32 phyAddr
,
339 UINT16 ctrlRegval
, statRegval
, regval
, regval4
, regval5
;
341 /* check the parameters */
342 if ((linkUp
== NULL
) ||
343 (speed100
== NULL
) ||
344 (fullDuplex
== NULL
) ||
355 if ((phyAddr
< IXP425_ETH_ACC_MII_MAX_ADDR
) &&
356 (ixEthMiiPhyId
[phyAddr
] != IX_ETH_MII_INVALID_PHY_ID
))
358 if ((ixEthMiiPhyId
[phyAddr
] == IX_ETH_MII_LXT971_PHY_ID
) ||
359 (ixEthMiiPhyId
[phyAddr
] == IX_ETH_MII_LXT972_PHY_ID
) ||
360 (ixEthMiiPhyId
[phyAddr
] == IX_ETH_MII_LXT9785_PHY_ID
)
363 /* --------------------------------------------------*/
364 /* Retrieve information from PHY specific register */
365 /* --------------------------------------------------*/
366 if (ixEthAccMiiReadRtn(phyAddr
,
367 IX_ETH_MII_STAT2_REG
,
368 ®val
) != IX_ETH_ACC_SUCCESS
)
372 *linkUp
= ((regval
& IX_ETH_MII_SR2_LINK
) != 0);
373 *speed100
= ((regval
& IX_ETH_MII_SR2_100
) != 0);
374 *fullDuplex
= ((regval
& IX_ETH_MII_SR2_FD
) != 0);
375 *autoneg
= ((regval
& IX_ETH_MII_SR2_AUTO
) != 0);
377 } /* end of if(ixEthMiiPhyId) */
380 /* ----------------------------------------------------*/
381 /* Retrieve information from status and ctrl registers */
382 /* ----------------------------------------------------*/
383 if (ixEthAccMiiReadRtn(phyAddr
,
385 &ctrlRegval
) != IX_ETH_ACC_SUCCESS
)
389 ixEthAccMiiReadRtn(phyAddr
, IX_ETH_MII_STAT_REG
, &statRegval
);
391 *linkUp
= ((statRegval
& IX_ETH_MII_SR_LINK_STATUS
) != 0);
394 *autoneg
= ((ctrlRegval
& IX_ETH_MII_CR_AUTO_EN
) != 0) &&
395 ((statRegval
& IX_ETH_MII_SR_AUTO_SEL
) != 0) &&
396 ((statRegval
& IX_ETH_MII_SR_AUTO_NEG
) != 0);
400 /* mask the current stat values with the capabilities */
401 ixEthAccMiiReadRtn(phyAddr
, IX_ETH_MII_AN_ADS_REG
, ®val4
);
402 ixEthAccMiiReadRtn(phyAddr
, IX_ETH_MII_AN_PRTN_REG
, ®val5
);
403 /* merge the flags from the 3 registers */
404 regval
= (statRegval
& ((regval4
& regval5
) << 6));
405 /* initialise from status register values */
406 if ((regval
& IX_ETH_MII_SR_TX_FULL_DPX
) != 0)
408 /* 100 Base X full dplx */
413 if ((regval
& IX_ETH_MII_SR_TX_HALF_DPX
) != 0)
415 /* 100 Base X half dplx */
419 if ((regval
& IX_ETH_MII_SR_10T_FULL_DPX
) != 0)
421 /* 10 mb full dplx */
425 if ((regval
& IX_ETH_MII_SR_10T_HALF_DPX
) != 0)
427 /* 10 mb half dplx */
430 } /* end of if(autoneg) */
433 /* autonegotiate not complete, return setup parameters */
434 *speed100
= ((ctrlRegval
& IX_ETH_MII_CR_100
) != 0);
435 *fullDuplex
= ((ctrlRegval
& IX_ETH_MII_CR_FDX
) != 0);
437 } /* end of if(linkUp) */
438 } /* end of if-else(ixEthMiiPhyId) */
439 } /* end of if(phyAddr) */
443 } /* end of if-else(phyAddr) */
447 /*****************************************************************
449 * Link state display functions
453 ixEthMiiPhyShow (UINT32 phyAddr
)
455 BOOL linkUp
, speed100
, fullDuplex
, autoneg
;
460 ixEthAccMiiReadRtn(phyAddr
, IX_ETH_MII_STAT_REG
, &sregval
);
461 ixEthAccMiiReadRtn(phyAddr
, IX_ETH_MII_CTRL_REG
, &cregval
);
463 /* get link information */
464 if (ixEthMiiLinkStatus(phyAddr
,
468 &autoneg
) != IX_ETH_ACC_SUCCESS
)
470 printf("PHY Status unknown\n");
474 printf("PHY ID [phyAddr]: %8.8x\n",ixEthMiiPhyId
[phyAddr
]);
475 printf( " Status reg: %4.4x\n",sregval
);
476 printf( " control reg: %4.4x\n",cregval
);
477 /* display link information */
478 printf("PHY Status:\n");
479 printf(" Link is %s\n",
480 (linkUp
? "Up" : "Down"));
481 if((sregval
& IX_ETH_MII_SR_REMOTE_FAULT
) != 0)
483 printf(" Remote fault detected\n");
485 printf(" Auto Negotiation %s\n",
486 (autoneg
? "Completed" : "Not Completed"));
488 printf("PHY Configuration:\n");
489 printf(" Speed %sMb/s\n",
490 (speed100
? "100" : "10"));
491 printf(" %s Duplex\n",
492 (fullDuplex
? "Full" : "Half"));
493 printf(" Auto Negotiation %s\n",
494 (autoneg
? "Enabled" : "Disabled"));