blob: 27f3548ce0b075f5d5e8d94508932be577f81797 [file] [log] [blame]
Wolfgang Denk4646d2a2006-05-30 15:56:48 +02001/**
2 * @file IxEthMii.c
3 *
4 * @author Intel Corporation
5 * @date
6 *
7 * @brief MII control functions
8 *
9 * Design Notes:
10 *
11 *
12 * @par
13 * IXP400 SW Release version 2.0
14 *
15 * -- Copyright Notice --
16 *
17 * @par
18 * Copyright 2001-2005, Intel Corporation.
19 * All rights reserved.
20 *
21 * @par
Wolfgang Denkc57eadc2013-07-28 22:12:47 +020022 * SPDX-License-Identifier: BSD-3-Clause
Wolfgang Denk4646d2a2006-05-30 15:56:48 +020023 * @par
24 * -- End of Copyright Notice --
25 */
26
27#include "IxOsal.h"
28
29#include "IxEthAcc.h"
30#include "IxEthMii_p.h"
31
32#ifdef __wince
33#include "IxOsPrintf.h"
34#endif
35
36/* Array to store the phy IDs of the discovered phys */
37PRIVATE UINT32 ixEthMiiPhyId[IXP425_ETH_ACC_MII_MAX_ADDR];
38
39/*********************************************************
40 *
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
York Sun4a598092013-04-01 11:29:11 -070044 * corresponding entry in the array is set to true.
Wolfgang Denk4646d2a2006-05-30 15:56:48 +020045 *
46 */
47
48PUBLIC IX_STATUS
49ixEthMiiPhyScan(BOOL phyPresent[], UINT32 maxPhyCount)
50{
51 UINT32 i;
52 UINT16 regval, regvalId1, regvalId2;
53
54 /*Search for PHYs on the MII*/
55 /*Search for existant phys on the MDIO bus*/
56
57 if ((phyPresent == NULL) ||
58 (maxPhyCount > IXP425_ETH_ACC_MII_MAX_ADDR))
59 {
60 return IX_FAIL;
61 }
62
63 /* fill the array */
64 for(i=0;
65 i<IXP425_ETH_ACC_MII_MAX_ADDR;
66 i++)
67 {
York Sun4a598092013-04-01 11:29:11 -070068 phyPresent[i] = false;
Wolfgang Denk4646d2a2006-05-30 15:56:48 +020069 }
70
71 /* iterate through the PHY addresses */
72 for(i=0;
73 maxPhyCount > 0 && i<IXP425_ETH_ACC_MII_MAX_ADDR;
74 i++)
75 {
76 ixEthMiiPhyId[i] = IX_ETH_MII_INVALID_PHY_ID;
77 if(ixEthAccMiiReadRtn(i,
78 IX_ETH_MII_CTRL_REG,
79 &regval) == IX_ETH_ACC_SUCCESS)
80 {
81 if((regval & 0xffff) != 0xffff)
82 {
83 maxPhyCount--;
84 /*Need to read the register twice here to flush PHY*/
85 ixEthAccMiiReadRtn(i, IX_ETH_MII_PHY_ID1_REG, &regvalId1);
86 ixEthAccMiiReadRtn(i, IX_ETH_MII_PHY_ID1_REG, &regvalId1);
87 ixEthAccMiiReadRtn(i, IX_ETH_MII_PHY_ID2_REG, &regvalId2);
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)
95 )
96 {
97 /* supported phy */
York Sun4a598092013-04-01 11:29:11 -070098 phyPresent[i] = true;
Wolfgang Denk4646d2a2006-05-30 15:56:48 +020099 } /* end of if(ixEthMiiPhyId) */
100 else
101 {
102 if (ixEthMiiPhyId[i] != IX_ETH_MII_INVALID_PHY_ID)
103 {
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;
York Sun4a598092013-04-01 11:29:11 -0700110 phyPresent[i] = true;
Wolfgang Denk4646d2a2006-05-30 15:56:48 +0200111 }
112 }
113 }
114 }
115 }
116 return IX_SUCCESS;
117}
118
119/************************************************************
120 *
121 * Configure the PHY at the specified address
122 *
123 */
124PUBLIC IX_STATUS
125ixEthMiiPhyConfig(UINT32 phyAddr,
126 BOOL speed100,
127 BOOL fullDuplex,
128 BOOL autonegotiate)
129{
130 UINT16 regval=0;
131
132 /* parameter check */
133 if ((phyAddr < IXP425_ETH_ACC_MII_MAX_ADDR) &&
134 (ixEthMiiPhyId[phyAddr] != IX_ETH_MII_INVALID_PHY_ID))
135 {
136 /*
137 * set the control register
138 */
139 if(autonegotiate)
140 {
141 regval |= IX_ETH_MII_CR_AUTO_EN | IX_ETH_MII_CR_RESTART;
142 }
143 else
144 {
145 if(speed100)
146 {
147 regval |= IX_ETH_MII_CR_100;
148 }
149 if(fullDuplex)
150 {
151 regval |= IX_ETH_MII_CR_FDX;
152 }
153 } /* end of if-else() */
154 if (ixEthAccMiiWriteRtn(phyAddr,
155 IX_ETH_MII_CTRL_REG,
156 regval) == IX_ETH_ACC_SUCCESS)
157 {
158 return IX_SUCCESS;
159 }
160 } /* end of if(phyAddr) */
161 return IX_FAIL;
162}
163
164/******************************************************************
165 *
166 * Enable the PHY Loopback at the specified address
167 */
168PUBLIC IX_STATUS
169ixEthMiiPhyLoopbackEnable (UINT32 phyAddr)
170{
171 UINT16 regval ;
172
173 if ((phyAddr < IXP425_ETH_ACC_MII_MAX_ADDR) &&
174 (IX_ETH_MII_INVALID_PHY_ID != ixEthMiiPhyId[phyAddr]))
175 {
176 /* read/write the control register */
177 if(ixEthAccMiiReadRtn (phyAddr,
178 IX_ETH_MII_CTRL_REG,
179 &regval)
180 == IX_ETH_ACC_SUCCESS)
181 {
182 if(ixEthAccMiiWriteRtn (phyAddr,
183 IX_ETH_MII_CTRL_REG,
184 regval | IX_ETH_MII_CR_LOOPBACK)
185 == IX_ETH_ACC_SUCCESS)
186 {
187 return IX_SUCCESS;
188 }
189 }
190 }
191 return IX_FAIL;
192}
193
194/******************************************************************
195 *
196 * Disable the PHY Loopback at the specified address
197 */
198PUBLIC IX_STATUS
199ixEthMiiPhyLoopbackDisable (UINT32 phyAddr)
200{
201 UINT16 regval ;
202
203 if ((phyAddr < IXP425_ETH_ACC_MII_MAX_ADDR) &&
204 (IX_ETH_MII_INVALID_PHY_ID != ixEthMiiPhyId[phyAddr]))
205 {
206 /* read/write the control register */
207 if(ixEthAccMiiReadRtn (phyAddr,
208 IX_ETH_MII_CTRL_REG,
209 &regval)
210 == IX_ETH_ACC_SUCCESS)
211 {
212 if(ixEthAccMiiWriteRtn (phyAddr,
213 IX_ETH_MII_CTRL_REG,
214 regval & (~IX_ETH_MII_CR_LOOPBACK))
215 == IX_ETH_ACC_SUCCESS)
216 {
217 return IX_SUCCESS;
218 }
219 }
220 }
221 return IX_FAIL;
222}
223
224/******************************************************************
225 *
226 * Reset the PHY at the specified address
227 */
228PUBLIC IX_STATUS
229ixEthMiiPhyReset(UINT32 phyAddr)
230{
231 UINT32 timeout;
232 UINT16 regval;
233
234 if ((phyAddr < IXP425_ETH_ACC_MII_MAX_ADDR) &&
235 (ixEthMiiPhyId[phyAddr] != IX_ETH_MII_INVALID_PHY_ID))
236 {
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)
242 )
243 {
244 /* use the control register to reset the phy */
245 ixEthAccMiiWriteRtn(phyAddr,
246 IX_ETH_MII_CTRL_REG,
247 IX_ETH_MII_CR_RESET);
248
249 /* poll until the reset bit is cleared */
250 timeout = 0;
251 do
252 {
253 ixOsalSleep (IX_ETH_MII_RESET_POLL_MS);
254
255 /* read the control register and check for timeout */
256 ixEthAccMiiReadRtn(phyAddr,
257 IX_ETH_MII_CTRL_REG,
258 &regval);
259 if ((regval & IX_ETH_MII_CR_RESET) == 0)
260 {
261 /* timeout bit is self-cleared */
262 break;
263 }
264 timeout += IX_ETH_MII_RESET_POLL_MS;
265 }
266 while (timeout < IX_ETH_MII_RESET_DELAY_MS);
267
268 /* check for timeout */
269 if (timeout >= IX_ETH_MII_RESET_DELAY_MS)
270 {
271 ixEthAccMiiWriteRtn(phyAddr, IX_ETH_MII_CTRL_REG,
272 IX_ETH_MII_CR_NORM_EN);
273 return IX_FAIL;
274 }
275
276 return IX_SUCCESS;
277 } /* end of if(ixEthMiiPhyId) */
278 else if (ixEthMiiPhyId[phyAddr] == IX_ETH_MII_KS8995_PHY_ID)
279 {
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);
283 return IX_SUCCESS;
284 }
285 else
286 {
287 /* unknown PHY, set the control register reset bit,
288 * wait 2 s. and clear the control register.
289 */
290 ixEthAccMiiWriteRtn(phyAddr, IX_ETH_MII_CTRL_REG,
291 IX_ETH_MII_CR_RESET);
292
293 ixOsalSleep (IX_ETH_MII_RESET_DELAY_MS);
294
295 ixEthAccMiiWriteRtn(phyAddr, IX_ETH_MII_CTRL_REG,
296 IX_ETH_MII_CR_NORM_EN);
297 return IX_SUCCESS;
298 } /* end of if-else(ixEthMiiPhyId) */
299 } /* end of if(phyAddr) */
300 return IX_FAIL;
301}
302
303/*****************************************************************
304 *
305 * Link state query functions
306 */
307
308PUBLIC IX_STATUS
309ixEthMiiLinkStatus(UINT32 phyAddr,
310 BOOL *linkUp,
311 BOOL *speed100,
312 BOOL *fullDuplex,
313 BOOL *autoneg)
314{
315 UINT16 ctrlRegval, statRegval, regval, regval4, regval5;
316
317 /* check the parameters */
318 if ((linkUp == NULL) ||
319 (speed100 == NULL) ||
320 (fullDuplex == NULL) ||
321 (autoneg == NULL))
322 {
323 return IX_FAIL;
324 }
325
York Sun4a598092013-04-01 11:29:11 -0700326 *linkUp = false;
327 *speed100 = false;
328 *fullDuplex = false;
329 *autoneg = false;
Wolfgang Denk4646d2a2006-05-30 15:56:48 +0200330
331 if ((phyAddr < IXP425_ETH_ACC_MII_MAX_ADDR) &&
332 (ixEthMiiPhyId[phyAddr] != IX_ETH_MII_INVALID_PHY_ID))
333 {
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)
337 )
338 {
339 /* --------------------------------------------------*/
340 /* Retrieve information from PHY specific register */
341 /* --------------------------------------------------*/
342 if (ixEthAccMiiReadRtn(phyAddr,
343 IX_ETH_MII_STAT2_REG,
344 &regval) != IX_ETH_ACC_SUCCESS)
345 {
346 return IX_FAIL;
347 }
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);
352 return IX_SUCCESS;
353 } /* end of if(ixEthMiiPhyId) */
354 else
355 {
356 /* ----------------------------------------------------*/
357 /* Retrieve information from status and ctrl registers */
358 /* ----------------------------------------------------*/
359 if (ixEthAccMiiReadRtn(phyAddr,
360 IX_ETH_MII_CTRL_REG,
361 &ctrlRegval) != IX_ETH_ACC_SUCCESS)
362 {
363 return IX_FAIL;
364 }
365 ixEthAccMiiReadRtn(phyAddr, IX_ETH_MII_STAT_REG, &statRegval);
366
367 *linkUp = ((statRegval & IX_ETH_MII_SR_LINK_STATUS) != 0);
368 if (*linkUp)
369 {
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);
373
374 if (*autoneg)
375 {
376 /* mask the current stat values with the capabilities */
377 ixEthAccMiiReadRtn(phyAddr, IX_ETH_MII_AN_ADS_REG, &regval4);
378 ixEthAccMiiReadRtn(phyAddr, IX_ETH_MII_AN_PRTN_REG, &regval5);
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)
383 {
384 /* 100 Base X full dplx */
York Sun4a598092013-04-01 11:29:11 -0700385 *speed100 = true;
386 *fullDuplex = true;
Wolfgang Denk4646d2a2006-05-30 15:56:48 +0200387 return IX_SUCCESS;
388 }
389 if ((regval & IX_ETH_MII_SR_TX_HALF_DPX) != 0)
390 {
391 /* 100 Base X half dplx */
York Sun4a598092013-04-01 11:29:11 -0700392 *speed100 = true;
Wolfgang Denk4646d2a2006-05-30 15:56:48 +0200393 return IX_SUCCESS;
394 }
395 if ((regval & IX_ETH_MII_SR_10T_FULL_DPX) != 0)
396 {
397 /* 10 mb full dplx */
York Sun4a598092013-04-01 11:29:11 -0700398 *fullDuplex = true;
Wolfgang Denk4646d2a2006-05-30 15:56:48 +0200399 return IX_SUCCESS;
400 }
401 if ((regval & IX_ETH_MII_SR_10T_HALF_DPX) != 0)
402 {
403 /* 10 mb half dplx */
404 return IX_SUCCESS;
405 }
406 } /* end of if(autoneg) */
407 else
408 {
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);
412 }
413 } /* end of if(linkUp) */
414 } /* end of if-else(ixEthMiiPhyId) */
415 } /* end of if(phyAddr) */
416 else
417 {
418 return IX_FAIL;
419 } /* end of if-else(phyAddr) */
420 return IX_SUCCESS;
421}
422
423/*****************************************************************
424 *
425 * Link state display functions
426 */
427
428PUBLIC IX_STATUS
429ixEthMiiPhyShow (UINT32 phyAddr)
430{
431 BOOL linkUp, speed100, fullDuplex, autoneg;
432 UINT16 cregval;
433 UINT16 sregval;
434
435
436 ixEthAccMiiReadRtn(phyAddr, IX_ETH_MII_STAT_REG, &sregval);
437 ixEthAccMiiReadRtn(phyAddr, IX_ETH_MII_CTRL_REG, &cregval);
438
439 /* get link information */
440 if (ixEthMiiLinkStatus(phyAddr,
441 &linkUp,
442 &speed100,
443 &fullDuplex,
444 &autoneg) != IX_ETH_ACC_SUCCESS)
445 {
446 printf("PHY Status unknown\n");
447 return IX_FAIL;
448 }
449
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)
458 {
459 printf(" Remote fault detected\n");
460 }
461 printf(" Auto Negotiation %s\n",
462 (autoneg ? "Completed" : "Not Completed"));
463
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"));
471 return IX_SUCCESS;
472}
473