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 * SPDX-License-Identifier: BSD-3-Clause
24 * -- End of Copyright Notice --
30 #include "IxEthMii_p.h"
33 #include "IxOsPrintf.h"
36 /* Array to store the phy IDs of the discovered phys */
37 PRIVATE UINT32 ixEthMiiPhyId[IXP425_ETH_ACC_MII_MAX_ADDR];
39 /*********************************************************
41 * Scan for PHYs on the MII bus. This function returns
42 * an array of booleans, one for each PHY address.
43 * If a PHY is found at a particular address, the
44 * corresponding entry in the array is set to true.
49 ixEthMiiPhyScan(BOOL phyPresent[], UINT32 maxPhyCount)
52 UINT16 regval, regvalId1, regvalId2;
54 /*Search for PHYs on the MII*/
55 /*Search for existant phys on the MDIO bus*/
57 if ((phyPresent == NULL) ||
58 (maxPhyCount > IXP425_ETH_ACC_MII_MAX_ADDR))
65 i<IXP425_ETH_ACC_MII_MAX_ADDR;
68 phyPresent[i] = false;
71 /* iterate through the PHY addresses */
73 maxPhyCount > 0 && i<IXP425_ETH_ACC_MII_MAX_ADDR;
76 ixEthMiiPhyId[i] = IX_ETH_MII_INVALID_PHY_ID;
77 if(ixEthAccMiiReadRtn(i,
79 ®val) == IX_ETH_ACC_SUCCESS)
81 if((regval & 0xffff) != 0xffff)
84 /*Need to read the register twice here to flush PHY*/
85 ixEthAccMiiReadRtn(i, IX_ETH_MII_PHY_ID1_REG, ®valId1);
86 ixEthAccMiiReadRtn(i, IX_ETH_MII_PHY_ID1_REG, ®valId1);
87 ixEthAccMiiReadRtn(i, IX_ETH_MII_PHY_ID2_REG, ®valId2);
88 ixEthMiiPhyId[i] = (regvalId1 << IX_ETH_MII_REG_SHL) | regvalId2;
89 if ((ixEthMiiPhyId[i] == IX_ETH_MII_KS8995_PHY_ID)
90 || (ixEthMiiPhyId[i] == IX_ETH_MII_LXT971_PHY_ID)
91 || (ixEthMiiPhyId[i] == IX_ETH_MII_LXT972_PHY_ID)
92 || (ixEthMiiPhyId[i] == IX_ETH_MII_LXT973_PHY_ID)
93 || (ixEthMiiPhyId[i] == IX_ETH_MII_LXT973A3_PHY_ID)
94 || (ixEthMiiPhyId[i] == IX_ETH_MII_LXT9785_PHY_ID)
99 } /* end of if(ixEthMiiPhyId) */
102 if (ixEthMiiPhyId[i] != IX_ETH_MII_INVALID_PHY_ID)
104 /* unsupported phy */
105 ixOsalLog (IX_OSAL_LOG_LVL_ERROR,
106 IX_OSAL_LOG_DEV_STDOUT,
107 "ixEthMiiPhyScan : unexpected Mii PHY ID %8.8x\n",
108 ixEthMiiPhyId[i], 2, 3, 4, 5, 6);
109 ixEthMiiPhyId[i] = IX_ETH_MII_UNKNOWN_PHY_ID;
110 phyPresent[i] = true;
119 /************************************************************
121 * Configure the PHY at the specified address
125 ixEthMiiPhyConfig(UINT32 phyAddr,
132 /* parameter check */
133 if ((phyAddr < IXP425_ETH_ACC_MII_MAX_ADDR) &&
134 (ixEthMiiPhyId[phyAddr] != IX_ETH_MII_INVALID_PHY_ID))
137 * set the control register
141 regval |= IX_ETH_MII_CR_AUTO_EN | IX_ETH_MII_CR_RESTART;
147 regval |= IX_ETH_MII_CR_100;
151 regval |= IX_ETH_MII_CR_FDX;
153 } /* end of if-else() */
154 if (ixEthAccMiiWriteRtn(phyAddr,
156 regval) == IX_ETH_ACC_SUCCESS)
160 } /* end of if(phyAddr) */
164 /******************************************************************
166 * Enable the PHY Loopback at the specified address
169 ixEthMiiPhyLoopbackEnable (UINT32 phyAddr)
173 if ((phyAddr < IXP425_ETH_ACC_MII_MAX_ADDR) &&
174 (IX_ETH_MII_INVALID_PHY_ID != ixEthMiiPhyId[phyAddr]))
176 /* read/write the control register */
177 if(ixEthAccMiiReadRtn (phyAddr,
180 == IX_ETH_ACC_SUCCESS)
182 if(ixEthAccMiiWriteRtn (phyAddr,
184 regval | IX_ETH_MII_CR_LOOPBACK)
185 == IX_ETH_ACC_SUCCESS)
194 /******************************************************************
196 * Disable the PHY Loopback at the specified address
199 ixEthMiiPhyLoopbackDisable (UINT32 phyAddr)
203 if ((phyAddr < IXP425_ETH_ACC_MII_MAX_ADDR) &&
204 (IX_ETH_MII_INVALID_PHY_ID != ixEthMiiPhyId[phyAddr]))
206 /* read/write the control register */
207 if(ixEthAccMiiReadRtn (phyAddr,
210 == IX_ETH_ACC_SUCCESS)
212 if(ixEthAccMiiWriteRtn (phyAddr,
214 regval & (~IX_ETH_MII_CR_LOOPBACK))
215 == IX_ETH_ACC_SUCCESS)
224 /******************************************************************
226 * Reset the PHY at the specified address
229 ixEthMiiPhyReset(UINT32 phyAddr)
234 if ((phyAddr < IXP425_ETH_ACC_MII_MAX_ADDR) &&
235 (ixEthMiiPhyId[phyAddr] != IX_ETH_MII_INVALID_PHY_ID))
237 if ((ixEthMiiPhyId[phyAddr] == IX_ETH_MII_LXT971_PHY_ID) ||
238 (ixEthMiiPhyId[phyAddr] == IX_ETH_MII_LXT972_PHY_ID) ||
239 (ixEthMiiPhyId[phyAddr] == IX_ETH_MII_LXT973_PHY_ID) ||
240 (ixEthMiiPhyId[phyAddr] == IX_ETH_MII_LXT973A3_PHY_ID) ||
241 (ixEthMiiPhyId[phyAddr] == IX_ETH_MII_LXT9785_PHY_ID)
244 /* use the control register to reset the phy */
245 ixEthAccMiiWriteRtn(phyAddr,
247 IX_ETH_MII_CR_RESET);
249 /* poll until the reset bit is cleared */
253 ixOsalSleep (IX_ETH_MII_RESET_POLL_MS);
255 /* read the control register and check for timeout */
256 ixEthAccMiiReadRtn(phyAddr,
259 if ((regval & IX_ETH_MII_CR_RESET) == 0)
261 /* timeout bit is self-cleared */
264 timeout += IX_ETH_MII_RESET_POLL_MS;
266 while (timeout < IX_ETH_MII_RESET_DELAY_MS);
268 /* check for timeout */
269 if (timeout >= IX_ETH_MII_RESET_DELAY_MS)
271 ixEthAccMiiWriteRtn(phyAddr, IX_ETH_MII_CTRL_REG,
272 IX_ETH_MII_CR_NORM_EN);
277 } /* end of if(ixEthMiiPhyId) */
278 else if (ixEthMiiPhyId[phyAddr] == IX_ETH_MII_KS8995_PHY_ID)
280 /* reset bit is reserved, just reset the control register */
281 ixEthAccMiiWriteRtn(phyAddr, IX_ETH_MII_CTRL_REG,
282 IX_ETH_MII_CR_NORM_EN);
287 /* unknown PHY, set the control register reset bit,
288 * wait 2 s. and clear the control register.
290 ixEthAccMiiWriteRtn(phyAddr, IX_ETH_MII_CTRL_REG,
291 IX_ETH_MII_CR_RESET);
293 ixOsalSleep (IX_ETH_MII_RESET_DELAY_MS);
295 ixEthAccMiiWriteRtn(phyAddr, IX_ETH_MII_CTRL_REG,
296 IX_ETH_MII_CR_NORM_EN);
298 } /* end of if-else(ixEthMiiPhyId) */
299 } /* end of if(phyAddr) */
303 /*****************************************************************
305 * Link state query functions
309 ixEthMiiLinkStatus(UINT32 phyAddr,
315 UINT16 ctrlRegval, statRegval, regval, regval4, regval5;
317 /* check the parameters */
318 if ((linkUp == NULL) ||
319 (speed100 == NULL) ||
320 (fullDuplex == NULL) ||
331 if ((phyAddr < IXP425_ETH_ACC_MII_MAX_ADDR) &&
332 (ixEthMiiPhyId[phyAddr] != IX_ETH_MII_INVALID_PHY_ID))
334 if ((ixEthMiiPhyId[phyAddr] == IX_ETH_MII_LXT971_PHY_ID) ||
335 (ixEthMiiPhyId[phyAddr] == IX_ETH_MII_LXT972_PHY_ID) ||
336 (ixEthMiiPhyId[phyAddr] == IX_ETH_MII_LXT9785_PHY_ID)
339 /* --------------------------------------------------*/
340 /* Retrieve information from PHY specific register */
341 /* --------------------------------------------------*/
342 if (ixEthAccMiiReadRtn(phyAddr,
343 IX_ETH_MII_STAT2_REG,
344 ®val) != IX_ETH_ACC_SUCCESS)
348 *linkUp = ((regval & IX_ETH_MII_SR2_LINK) != 0);
349 *speed100 = ((regval & IX_ETH_MII_SR2_100) != 0);
350 *fullDuplex = ((regval & IX_ETH_MII_SR2_FD) != 0);
351 *autoneg = ((regval & IX_ETH_MII_SR2_AUTO) != 0);
353 } /* end of if(ixEthMiiPhyId) */
356 /* ----------------------------------------------------*/
357 /* Retrieve information from status and ctrl registers */
358 /* ----------------------------------------------------*/
359 if (ixEthAccMiiReadRtn(phyAddr,
361 &ctrlRegval) != IX_ETH_ACC_SUCCESS)
365 ixEthAccMiiReadRtn(phyAddr, IX_ETH_MII_STAT_REG, &statRegval);
367 *linkUp = ((statRegval & IX_ETH_MII_SR_LINK_STATUS) != 0);
370 *autoneg = ((ctrlRegval & IX_ETH_MII_CR_AUTO_EN) != 0) &&
371 ((statRegval & IX_ETH_MII_SR_AUTO_SEL) != 0) &&
372 ((statRegval & IX_ETH_MII_SR_AUTO_NEG) != 0);
376 /* mask the current stat values with the capabilities */
377 ixEthAccMiiReadRtn(phyAddr, IX_ETH_MII_AN_ADS_REG, ®val4);
378 ixEthAccMiiReadRtn(phyAddr, IX_ETH_MII_AN_PRTN_REG, ®val5);
379 /* merge the flags from the 3 registers */
380 regval = (statRegval & ((regval4 & regval5) << 6));
381 /* initialise from status register values */
382 if ((regval & IX_ETH_MII_SR_TX_FULL_DPX) != 0)
384 /* 100 Base X full dplx */
389 if ((regval & IX_ETH_MII_SR_TX_HALF_DPX) != 0)
391 /* 100 Base X half dplx */
395 if ((regval & IX_ETH_MII_SR_10T_FULL_DPX) != 0)
397 /* 10 mb full dplx */
401 if ((regval & IX_ETH_MII_SR_10T_HALF_DPX) != 0)
403 /* 10 mb half dplx */
406 } /* end of if(autoneg) */
409 /* autonegotiate not complete, return setup parameters */
410 *speed100 = ((ctrlRegval & IX_ETH_MII_CR_100) != 0);
411 *fullDuplex = ((ctrlRegval & IX_ETH_MII_CR_FDX) != 0);
413 } /* end of if(linkUp) */
414 } /* end of if-else(ixEthMiiPhyId) */
415 } /* end of if(phyAddr) */
419 } /* end of if-else(phyAddr) */
423 /*****************************************************************
425 * Link state display functions
429 ixEthMiiPhyShow (UINT32 phyAddr)
431 BOOL linkUp, speed100, fullDuplex, autoneg;
436 ixEthAccMiiReadRtn(phyAddr, IX_ETH_MII_STAT_REG, &sregval);
437 ixEthAccMiiReadRtn(phyAddr, IX_ETH_MII_CTRL_REG, &cregval);
439 /* get link information */
440 if (ixEthMiiLinkStatus(phyAddr,
444 &autoneg) != IX_ETH_ACC_SUCCESS)
446 printf("PHY Status unknown\n");
450 printf("PHY ID [phyAddr]: %8.8x\n",ixEthMiiPhyId[phyAddr]);
451 printf( " Status reg: %4.4x\n",sregval);
452 printf( " control reg: %4.4x\n",cregval);
453 /* display link information */
454 printf("PHY Status:\n");
455 printf(" Link is %s\n",
456 (linkUp ? "Up" : "Down"));
457 if((sregval & IX_ETH_MII_SR_REMOTE_FAULT) != 0)
459 printf(" Remote fault detected\n");
461 printf(" Auto Negotiation %s\n",
462 (autoneg ? "Completed" : "Not Completed"));
464 printf("PHY Configuration:\n");
465 printf(" Speed %sMb/s\n",
466 (speed100 ? "100" : "10"));
467 printf(" %s Duplex\n",
468 (fullDuplex ? "Full" : "Half"));
469 printf(" Auto Negotiation %s\n",
470 (autoneg ? "Enabled" : "Disabled"));