]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/net/npe/IxEthMii.c
doc: SPI: Add qspi test details on AM43xx
[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  * SPDX-License-Identifier:     BSD-3-Clause
23  * @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 */
37 PRIVATE 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
44  * corresponding entry in the array is set to true.
45  *
46  */
47
48 PUBLIC IX_STATUS
49 ixEthMiiPhyScan(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     {
68         phyPresent[i] = false;
69     }
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 */
98                     phyPresent[i] = true;
99                 } /* 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;
110                         phyPresent[i] = true;
111                     }
112                 } 
113             }
114         }
115     }
116     return IX_SUCCESS;
117 }
118
119 /************************************************************
120  *
121  * Configure the PHY at the specified address
122  *
123  */
124 PUBLIC IX_STATUS
125 ixEthMiiPhyConfig(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  */
168 PUBLIC IX_STATUS
169 ixEthMiiPhyLoopbackEnable (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  */
198 PUBLIC IX_STATUS
199 ixEthMiiPhyLoopbackDisable (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  */
228 PUBLIC IX_STATUS
229 ixEthMiiPhyReset(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
308 PUBLIC IX_STATUS
309 ixEthMiiLinkStatus(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
326     *linkUp = false;
327     *speed100 = false;
328     *fullDuplex = false;
329     *autoneg = false;
330
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 */
385                         *speed100 = true;
386                         *fullDuplex = true;
387                         return IX_SUCCESS;
388                     }
389                     if ((regval & IX_ETH_MII_SR_TX_HALF_DPX) != 0)
390                     {
391                         /* 100 Base X half dplx */
392                         *speed100 = true;
393                         return IX_SUCCESS;
394                     }
395                     if ((regval & IX_ETH_MII_SR_10T_FULL_DPX) != 0)
396                     {
397                         /* 10 mb full dplx */
398                         *fullDuplex = true;
399                         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
428 PUBLIC IX_STATUS
429 ixEthMiiPhyShow (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