]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/net/npe/IxEthMii.c
Merge branch 'u-boot-imx/master' into 'u-boot-arm/master'
[karo-tx-uboot.git] / drivers / net / npe / IxEthMii.c
1 /**
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 */
61 PRIVATE 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
72 PUBLIC IX_STATUS
73 ixEthMiiPhyScan(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  */
148 PUBLIC IX_STATUS
149 ixEthMiiPhyConfig(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  */
192 PUBLIC IX_STATUS
193 ixEthMiiPhyLoopbackEnable (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  */
222 PUBLIC IX_STATUS
223 ixEthMiiPhyLoopbackDisable (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  */
252 PUBLIC IX_STATUS
253 ixEthMiiPhyReset(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
332 PUBLIC IX_STATUS
333 ixEthMiiLinkStatus(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
452 PUBLIC IX_STATUS
453 ixEthMiiPhyShow (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