blob: 4d92f17eef779a9943aaea344f451f6d3b6a44ee [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
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
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.
33 *
34 * @par
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
45 * SUCH DAMAGE.
46 *
47 * @par
48 * -- End of Copyright Notice --
49 */
50
51#include "IxOsal.h"
52
53#include "IxEthAcc.h"
54#include "IxEthMii_p.h"
55
56#ifdef __wince
57#include "IxOsPrintf.h"
58#endif
59
60/* Array to store the phy IDs of the discovered phys */
61PRIVATE UINT32 ixEthMiiPhyId[IXP425_ETH_ACC_MII_MAX_ADDR];
62
63/*********************************************************
64 *
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.
69 *
70 */
71
72PUBLIC IX_STATUS
73ixEthMiiPhyScan(BOOL phyPresent[], UINT32 maxPhyCount)
74{
75 UINT32 i;
76 UINT16 regval, regvalId1, regvalId2;
77
78 /*Search for PHYs on the MII*/
79 /*Search for existant phys on the MDIO bus*/
80
81 if ((phyPresent == NULL) ||
82 (maxPhyCount > IXP425_ETH_ACC_MII_MAX_ADDR))
83 {
84 return IX_FAIL;
85 }
86
87 /* fill the array */
88 for(i=0;
89 i<IXP425_ETH_ACC_MII_MAX_ADDR;
90 i++)
91 {
92 phyPresent[i] = FALSE;
93 }
94
95 /* iterate through the PHY addresses */
96 for(i=0;
97 maxPhyCount > 0 && i<IXP425_ETH_ACC_MII_MAX_ADDR;
98 i++)
99 {
100 ixEthMiiPhyId[i] = IX_ETH_MII_INVALID_PHY_ID;
101 if(ixEthAccMiiReadRtn(i,
102 IX_ETH_MII_CTRL_REG,
103 &regval) == IX_ETH_ACC_SUCCESS)
104 {
105 if((regval & 0xffff) != 0xffff)
106 {
107 maxPhyCount--;
108 /*Need to read the register twice here to flush PHY*/
109 ixEthAccMiiReadRtn(i, IX_ETH_MII_PHY_ID1_REG, &regvalId1);
110 ixEthAccMiiReadRtn(i, IX_ETH_MII_PHY_ID1_REG, &regvalId1);
111 ixEthAccMiiReadRtn(i, IX_ETH_MII_PHY_ID2_REG, &regvalId2);
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)
119 )
120 {
121 /* supported phy */
122 phyPresent[i] = TRUE;
123 } /* end of if(ixEthMiiPhyId) */
124 else
125 {
126 if (ixEthMiiPhyId[i] != IX_ETH_MII_INVALID_PHY_ID)
127 {
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;
135 }
136 }
137 }
138 }
139 }
140 return IX_SUCCESS;
141}
142
143/************************************************************
144 *
145 * Configure the PHY at the specified address
146 *
147 */
148PUBLIC IX_STATUS
149ixEthMiiPhyConfig(UINT32 phyAddr,
150 BOOL speed100,
151 BOOL fullDuplex,
152 BOOL autonegotiate)
153{
154 UINT16 regval=0;
155
156 /* parameter check */
157 if ((phyAddr < IXP425_ETH_ACC_MII_MAX_ADDR) &&
158 (ixEthMiiPhyId[phyAddr] != IX_ETH_MII_INVALID_PHY_ID))
159 {
160 /*
161 * set the control register
162 */
163 if(autonegotiate)
164 {
165 regval |= IX_ETH_MII_CR_AUTO_EN | IX_ETH_MII_CR_RESTART;
166 }
167 else
168 {
169 if(speed100)
170 {
171 regval |= IX_ETH_MII_CR_100;
172 }
173 if(fullDuplex)
174 {
175 regval |= IX_ETH_MII_CR_FDX;
176 }
177 } /* end of if-else() */
178 if (ixEthAccMiiWriteRtn(phyAddr,
179 IX_ETH_MII_CTRL_REG,
180 regval) == IX_ETH_ACC_SUCCESS)
181 {
182 return IX_SUCCESS;
183 }
184 } /* end of if(phyAddr) */
185 return IX_FAIL;
186}
187
188/******************************************************************
189 *
190 * Enable the PHY Loopback at the specified address
191 */
192PUBLIC IX_STATUS
193ixEthMiiPhyLoopbackEnable (UINT32 phyAddr)
194{
195 UINT16 regval ;
196
197 if ((phyAddr < IXP425_ETH_ACC_MII_MAX_ADDR) &&
198 (IX_ETH_MII_INVALID_PHY_ID != ixEthMiiPhyId[phyAddr]))
199 {
200 /* read/write the control register */
201 if(ixEthAccMiiReadRtn (phyAddr,
202 IX_ETH_MII_CTRL_REG,
203 &regval)
204 == IX_ETH_ACC_SUCCESS)
205 {
206 if(ixEthAccMiiWriteRtn (phyAddr,
207 IX_ETH_MII_CTRL_REG,
208 regval | IX_ETH_MII_CR_LOOPBACK)
209 == IX_ETH_ACC_SUCCESS)
210 {
211 return IX_SUCCESS;
212 }
213 }
214 }
215 return IX_FAIL;
216}
217
218/******************************************************************
219 *
220 * Disable the PHY Loopback at the specified address
221 */
222PUBLIC IX_STATUS
223ixEthMiiPhyLoopbackDisable (UINT32 phyAddr)
224{
225 UINT16 regval ;
226
227 if ((phyAddr < IXP425_ETH_ACC_MII_MAX_ADDR) &&
228 (IX_ETH_MII_INVALID_PHY_ID != ixEthMiiPhyId[phyAddr]))
229 {
230 /* read/write the control register */
231 if(ixEthAccMiiReadRtn (phyAddr,
232 IX_ETH_MII_CTRL_REG,
233 &regval)
234 == IX_ETH_ACC_SUCCESS)
235 {
236 if(ixEthAccMiiWriteRtn (phyAddr,
237 IX_ETH_MII_CTRL_REG,
238 regval & (~IX_ETH_MII_CR_LOOPBACK))
239 == IX_ETH_ACC_SUCCESS)
240 {
241 return IX_SUCCESS;
242 }
243 }
244 }
245 return IX_FAIL;
246}
247
248/******************************************************************
249 *
250 * Reset the PHY at the specified address
251 */
252PUBLIC IX_STATUS
253ixEthMiiPhyReset(UINT32 phyAddr)
254{
255 UINT32 timeout;
256 UINT16 regval;
257
258 if ((phyAddr < IXP425_ETH_ACC_MII_MAX_ADDR) &&
259 (ixEthMiiPhyId[phyAddr] != IX_ETH_MII_INVALID_PHY_ID))
260 {
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)
266 )
267 {
268 /* use the control register to reset the phy */
269 ixEthAccMiiWriteRtn(phyAddr,
270 IX_ETH_MII_CTRL_REG,
271 IX_ETH_MII_CR_RESET);
272
273 /* poll until the reset bit is cleared */
274 timeout = 0;
275 do
276 {
277 ixOsalSleep (IX_ETH_MII_RESET_POLL_MS);
278
279 /* read the control register and check for timeout */
280 ixEthAccMiiReadRtn(phyAddr,
281 IX_ETH_MII_CTRL_REG,
282 &regval);
283 if ((regval & IX_ETH_MII_CR_RESET) == 0)
284 {
285 /* timeout bit is self-cleared */
286 break;
287 }
288 timeout += IX_ETH_MII_RESET_POLL_MS;
289 }
290 while (timeout < IX_ETH_MII_RESET_DELAY_MS);
291
292 /* check for timeout */
293 if (timeout >= 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_FAIL;
298 }
299
300 return IX_SUCCESS;
301 } /* end of if(ixEthMiiPhyId) */
302 else if (ixEthMiiPhyId[phyAddr] == IX_ETH_MII_KS8995_PHY_ID)
303 {
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);
307 return IX_SUCCESS;
308 }
309 else
310 {
311 /* unknown PHY, set the control register reset bit,
312 * wait 2 s. and clear the control register.
313 */
314 ixEthAccMiiWriteRtn(phyAddr, IX_ETH_MII_CTRL_REG,
315 IX_ETH_MII_CR_RESET);
316
317 ixOsalSleep (IX_ETH_MII_RESET_DELAY_MS);
318
319 ixEthAccMiiWriteRtn(phyAddr, IX_ETH_MII_CTRL_REG,
320 IX_ETH_MII_CR_NORM_EN);
321 return IX_SUCCESS;
322 } /* end of if-else(ixEthMiiPhyId) */
323 } /* end of if(phyAddr) */
324 return IX_FAIL;
325}
326
327/*****************************************************************
328 *
329 * Link state query functions
330 */
331
332PUBLIC IX_STATUS
333ixEthMiiLinkStatus(UINT32 phyAddr,
334 BOOL *linkUp,
335 BOOL *speed100,
336 BOOL *fullDuplex,
337 BOOL *autoneg)
338{
339 UINT16 ctrlRegval, statRegval, regval, regval4, regval5;
340
341 /* check the parameters */
342 if ((linkUp == NULL) ||
343 (speed100 == NULL) ||
344 (fullDuplex == NULL) ||
345 (autoneg == NULL))
346 {
347 return IX_FAIL;
348 }
349
350 *linkUp = FALSE;
351 *speed100 = FALSE;
352 *fullDuplex = FALSE;
353 *autoneg = FALSE;
354
355 if ((phyAddr < IXP425_ETH_ACC_MII_MAX_ADDR) &&
356 (ixEthMiiPhyId[phyAddr] != IX_ETH_MII_INVALID_PHY_ID))
357 {
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)
361 )
362 {
363 /* --------------------------------------------------*/
364 /* Retrieve information from PHY specific register */
365 /* --------------------------------------------------*/
366 if (ixEthAccMiiReadRtn(phyAddr,
367 IX_ETH_MII_STAT2_REG,
368 &regval) != IX_ETH_ACC_SUCCESS)
369 {
370 return IX_FAIL;
371 }
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);
376 return IX_SUCCESS;
377 } /* end of if(ixEthMiiPhyId) */
378 else
379 {
380 /* ----------------------------------------------------*/
381 /* Retrieve information from status and ctrl registers */
382 /* ----------------------------------------------------*/
383 if (ixEthAccMiiReadRtn(phyAddr,
384 IX_ETH_MII_CTRL_REG,
385 &ctrlRegval) != IX_ETH_ACC_SUCCESS)
386 {
387 return IX_FAIL;
388 }
389 ixEthAccMiiReadRtn(phyAddr, IX_ETH_MII_STAT_REG, &statRegval);
390
391 *linkUp = ((statRegval & IX_ETH_MII_SR_LINK_STATUS) != 0);
392 if (*linkUp)
393 {
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);
397
398 if (*autoneg)
399 {
400 /* mask the current stat values with the capabilities */
401 ixEthAccMiiReadRtn(phyAddr, IX_ETH_MII_AN_ADS_REG, &regval4);
402 ixEthAccMiiReadRtn(phyAddr, IX_ETH_MII_AN_PRTN_REG, &regval5);
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)
407 {
408 /* 100 Base X full dplx */
409 *speed100 = TRUE;
410 *fullDuplex = TRUE;
411 return IX_SUCCESS;
412 }
413 if ((regval & IX_ETH_MII_SR_TX_HALF_DPX) != 0)
414 {
415 /* 100 Base X half dplx */
416 *speed100 = TRUE;
417 return IX_SUCCESS;
418 }
419 if ((regval & IX_ETH_MII_SR_10T_FULL_DPX) != 0)
420 {
421 /* 10 mb full dplx */
422 *fullDuplex = TRUE;
423 return IX_SUCCESS;
424 }
425 if ((regval & IX_ETH_MII_SR_10T_HALF_DPX) != 0)
426 {
427 /* 10 mb half dplx */
428 return IX_SUCCESS;
429 }
430 } /* end of if(autoneg) */
431 else
432 {
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);
436 }
437 } /* end of if(linkUp) */
438 } /* end of if-else(ixEthMiiPhyId) */
439 } /* end of if(phyAddr) */
440 else
441 {
442 return IX_FAIL;
443 } /* end of if-else(phyAddr) */
444 return IX_SUCCESS;
445}
446
447/*****************************************************************
448 *
449 * Link state display functions
450 */
451
452PUBLIC IX_STATUS
453ixEthMiiPhyShow (UINT32 phyAddr)
454{
455 BOOL linkUp, speed100, fullDuplex, autoneg;
456 UINT16 cregval;
457 UINT16 sregval;
458
459
460 ixEthAccMiiReadRtn(phyAddr, IX_ETH_MII_STAT_REG, &sregval);
461 ixEthAccMiiReadRtn(phyAddr, IX_ETH_MII_CTRL_REG, &cregval);
462
463 /* get link information */
464 if (ixEthMiiLinkStatus(phyAddr,
465 &linkUp,
466 &speed100,
467 &fullDuplex,
468 &autoneg) != IX_ETH_ACC_SUCCESS)
469 {
470 printf("PHY Status unknown\n");
471 return IX_FAIL;
472 }
473
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)
482 {
483 printf(" Remote fault detected\n");
484 }
485 printf(" Auto Negotiation %s\n",
486 (autoneg ? "Completed" : "Not Completed"));
487
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"));
495 return IX_SUCCESS;
496}
497