Merge branch 'master' of git://www.denx.de/git/u-boot-freebsd
[platform/kernel/u-boot.git] / drivers / net / bcm570x_autoneg.c
1 /******************************************************************************/
2 /*                                                                            */
3 /* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2001 Broadcom         */
4 /* Corporation.                                                               */
5 /* All rights reserved.                                                       */
6 /*                                                                            */
7 /* This program is free software; you can redistribute it and/or modify       */
8 /* it under the terms of the GNU General Public License as published by       */
9 /* the Free Software Foundation, located in the file LICENSE.                 */
10 /*                                                                            */
11 /* History:                                                                   */
12 /******************************************************************************/
13 #if !defined(CONFIG_NET_MULTI)
14 #if INCLUDE_TBI_SUPPORT
15 #include "bcm570x_autoneg.h"
16 #include "bcm570x_mm.h"
17
18
19 /******************************************************************************/
20 /* Description:                                                               */
21 /*                                                                            */
22 /* Return:                                                                    */
23 /******************************************************************************/
24 void
25 MM_AnTxConfig(
26     PAN_STATE_INFO pAnInfo)
27 {
28     PLM_DEVICE_BLOCK pDevice;
29
30     pDevice = (PLM_DEVICE_BLOCK) pAnInfo->pContext;
31
32     REG_WR(pDevice, MacCtrl.TxAutoNeg, (LM_UINT32) pAnInfo->TxConfig.AsUSHORT);
33
34     pDevice->MacMode |= MAC_MODE_SEND_CONFIGS;
35     REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode);
36 }
37
38
39 /******************************************************************************/
40 /* Description:                                                               */
41 /*                                                                            */
42 /* Return:                                                                    */
43 /******************************************************************************/
44 void
45 MM_AnTxIdle(
46     PAN_STATE_INFO pAnInfo)
47 {
48     PLM_DEVICE_BLOCK pDevice;
49
50     pDevice = (PLM_DEVICE_BLOCK) pAnInfo->pContext;
51
52     pDevice->MacMode &= ~MAC_MODE_SEND_CONFIGS;
53     REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode);
54 }
55
56
57 /******************************************************************************/
58 /* Description:                                                               */
59 /*                                                                            */
60 /* Return:                                                                    */
61 /******************************************************************************/
62 char
63 MM_AnRxConfig(
64     PAN_STATE_INFO pAnInfo,
65     unsigned short *pRxConfig)
66 {
67     PLM_DEVICE_BLOCK pDevice;
68     LM_UINT32 Value32;
69     char Retcode;
70
71     Retcode = AN_FALSE;
72
73     pDevice = (PLM_DEVICE_BLOCK) pAnInfo->pContext;
74
75     Value32 = REG_RD(pDevice, MacCtrl.Status);
76     if(Value32 & MAC_STATUS_RECEIVING_CFG)
77     {
78         Value32 = REG_RD(pDevice, MacCtrl.RxAutoNeg);
79         *pRxConfig = (unsigned short) Value32;
80
81         Retcode = AN_TRUE;
82     }
83
84     return Retcode;
85 }
86
87
88 /******************************************************************************/
89 /* Description:                                                               */
90 /*                                                                            */
91 /* Return:                                                                    */
92 /******************************************************************************/
93 void
94 AutonegInit(
95     PAN_STATE_INFO pAnInfo)
96 {
97     unsigned long j;
98
99     for(j = 0; j < sizeof(AN_STATE_INFO); j++)
100     {
101         ((unsigned char *) pAnInfo)[j] = 0;
102     }
103
104     /* Initialize the default advertisement register. */
105     pAnInfo->mr_adv_full_duplex = 1;
106     pAnInfo->mr_adv_sym_pause = 1;
107     pAnInfo->mr_adv_asym_pause = 1;
108     pAnInfo->mr_an_enable = 1;
109 }
110
111
112 /******************************************************************************/
113 /* Description:                                                               */
114 /*                                                                            */
115 /* Return:                                                                    */
116 /******************************************************************************/
117 AUTONEG_STATUS
118 Autoneg8023z(
119     PAN_STATE_INFO pAnInfo)
120 {
121     unsigned short RxConfig;
122     unsigned long Delta_us;
123     AUTONEG_STATUS AnRet;
124
125     /* Get the current time. */
126     if(pAnInfo->State == AN_STATE_UNKNOWN)
127     {
128         pAnInfo->RxConfig.AsUSHORT = 0;
129         pAnInfo->CurrentTime_us = 0;
130         pAnInfo->LinkTime_us = 0;
131         pAnInfo->AbilityMatchCfg = 0;
132         pAnInfo->AbilityMatchCnt = 0;
133         pAnInfo->AbilityMatch = AN_FALSE;
134         pAnInfo->IdleMatch = AN_FALSE;
135         pAnInfo->AckMatch = AN_FALSE;
136     }
137
138     /* Increment the timer tick.  This function is called every microsecon. */
139 /*    pAnInfo->CurrentTime_us++; */
140
141     /* Set the AbilityMatch, IdleMatch, and AckMatch flags if their */
142     /* corresponding conditions are satisfied. */
143     if(MM_AnRxConfig(pAnInfo, &RxConfig))
144     {
145         if(RxConfig != pAnInfo->AbilityMatchCfg)
146         {
147             pAnInfo->AbilityMatchCfg = RxConfig;
148             pAnInfo->AbilityMatch = AN_FALSE;
149             pAnInfo->AbilityMatchCnt = 0;
150         }
151         else
152         {
153             pAnInfo->AbilityMatchCnt++;
154             if(pAnInfo->AbilityMatchCnt > 1)
155             {
156                 pAnInfo->AbilityMatch = AN_TRUE;
157                 pAnInfo->AbilityMatchCfg = RxConfig;
158             }
159         }
160
161         if(RxConfig & AN_CONFIG_ACK)
162         {
163             pAnInfo->AckMatch = AN_TRUE;
164         }
165         else
166         {
167             pAnInfo->AckMatch = AN_FALSE;
168         }
169
170         pAnInfo->IdleMatch = AN_FALSE;
171     }
172     else
173     {
174         pAnInfo->IdleMatch = AN_TRUE;
175
176         pAnInfo->AbilityMatchCfg = 0;
177         pAnInfo->AbilityMatchCnt = 0;
178         pAnInfo->AbilityMatch = AN_FALSE;
179         pAnInfo->AckMatch = AN_FALSE;
180
181         RxConfig = 0;
182     }
183
184     /* Save the last Config. */
185     pAnInfo->RxConfig.AsUSHORT = RxConfig;
186
187     /* Default return code. */
188     AnRet = AUTONEG_STATUS_OK;
189
190     /* Autoneg state machine as defined in 802.3z section 37.3.1.5. */
191     switch(pAnInfo->State)
192     {
193         case AN_STATE_UNKNOWN:
194             if(pAnInfo->mr_an_enable || pAnInfo->mr_restart_an)
195             {
196                 pAnInfo->CurrentTime_us = 0;
197                 pAnInfo->State = AN_STATE_AN_ENABLE;
198             }
199
200             /* Fall through.*/
201
202         case AN_STATE_AN_ENABLE:
203             pAnInfo->mr_an_complete = AN_FALSE;
204             pAnInfo->mr_page_rx = AN_FALSE;
205
206             if(pAnInfo->mr_an_enable)
207             {
208                 pAnInfo->LinkTime_us = 0;
209                 pAnInfo->AbilityMatchCfg = 0;
210                 pAnInfo->AbilityMatchCnt = 0;
211                 pAnInfo->AbilityMatch = AN_FALSE;
212                 pAnInfo->IdleMatch = AN_FALSE;
213                 pAnInfo->AckMatch = AN_FALSE;
214
215                 pAnInfo->State = AN_STATE_AN_RESTART_INIT;
216             }
217             else
218             {
219                 pAnInfo->State = AN_STATE_DISABLE_LINK_OK;
220             }
221             break;
222
223         case AN_STATE_AN_RESTART_INIT:
224             pAnInfo->LinkTime_us = pAnInfo->CurrentTime_us;
225             pAnInfo->mr_np_loaded = AN_FALSE;
226
227             pAnInfo->TxConfig.AsUSHORT = 0;
228             MM_AnTxConfig(pAnInfo);
229
230             AnRet = AUTONEG_STATUS_TIMER_ENABLED;
231
232             pAnInfo->State = AN_STATE_AN_RESTART;
233
234             /* Fall through.*/
235
236         case AN_STATE_AN_RESTART:
237             /* Get the current time and compute the delta with the saved */
238             /* link timer. */
239             Delta_us = pAnInfo->CurrentTime_us - pAnInfo->LinkTime_us;
240             if(Delta_us > AN_LINK_TIMER_INTERVAL_US)
241             {
242                 pAnInfo->State = AN_STATE_ABILITY_DETECT_INIT;
243             }
244             else
245             {
246                 AnRet = AUTONEG_STATUS_TIMER_ENABLED;
247             }
248             break;
249
250         case AN_STATE_DISABLE_LINK_OK:
251             AnRet = AUTONEG_STATUS_DONE;
252             break;
253
254         case AN_STATE_ABILITY_DETECT_INIT:
255             /* Note: in the state diagram, this variable is set to */
256             /* mr_adv_ability<12>.  Is this right?. */
257             pAnInfo->mr_toggle_tx = AN_FALSE;
258
259             /* Send the config as advertised in the advertisement register. */
260             pAnInfo->TxConfig.AsUSHORT = 0;
261             pAnInfo->TxConfig.D5_FD = pAnInfo->mr_adv_full_duplex;
262             pAnInfo->TxConfig.D6_HD = pAnInfo->mr_adv_half_duplex;
263             pAnInfo->TxConfig.D7_PS1 = pAnInfo->mr_adv_sym_pause;
264             pAnInfo->TxConfig.D8_PS2 = pAnInfo->mr_adv_asym_pause;
265             pAnInfo->TxConfig.D12_RF1 = pAnInfo->mr_adv_remote_fault1;
266             pAnInfo->TxConfig.D13_RF2 = pAnInfo->mr_adv_remote_fault2;
267             pAnInfo->TxConfig.D15_NP = pAnInfo->mr_adv_next_page;
268
269             MM_AnTxConfig(pAnInfo);
270
271             pAnInfo->State = AN_STATE_ABILITY_DETECT;
272
273             break;
274
275         case AN_STATE_ABILITY_DETECT:
276             if(pAnInfo->AbilityMatch == AN_TRUE &&
277                 pAnInfo->RxConfig.AsUSHORT != 0)
278             {
279                 pAnInfo->State = AN_STATE_ACK_DETECT_INIT;
280             }
281
282             break;
283
284         case AN_STATE_ACK_DETECT_INIT:
285             pAnInfo->TxConfig.D14_ACK = 1;
286             MM_AnTxConfig(pAnInfo);
287
288             pAnInfo->State = AN_STATE_ACK_DETECT;
289
290             /* Fall through. */
291
292         case AN_STATE_ACK_DETECT:
293             if(pAnInfo->AckMatch == AN_TRUE)
294             {
295                 if((pAnInfo->RxConfig.AsUSHORT & ~AN_CONFIG_ACK) ==
296                     (pAnInfo->AbilityMatchCfg & ~AN_CONFIG_ACK))
297                 {
298                     pAnInfo->State = AN_STATE_COMPLETE_ACK_INIT;
299                 }
300                 else
301                 {
302                     pAnInfo->State = AN_STATE_AN_ENABLE;
303                 }
304             }
305             else if(pAnInfo->AbilityMatch == AN_TRUE &&
306                 pAnInfo->RxConfig.AsUSHORT == 0)
307             {
308                 pAnInfo->State = AN_STATE_AN_ENABLE;
309             }
310
311             break;
312
313         case AN_STATE_COMPLETE_ACK_INIT:
314             /* Make sure invalid bits are not set. */
315             if(pAnInfo->RxConfig.bits.D0 || pAnInfo->RxConfig.bits.D1 ||
316                 pAnInfo->RxConfig.bits.D2 || pAnInfo->RxConfig.bits.D3 ||
317                 pAnInfo->RxConfig.bits.D4 || pAnInfo->RxConfig.bits.D9 ||
318                 pAnInfo->RxConfig.bits.D10 || pAnInfo->RxConfig.bits.D11)
319             {
320                 AnRet = AUTONEG_STATUS_FAILED;
321                 break;
322             }
323
324             /* Set up the link partner advertisement register. */
325             pAnInfo->mr_lp_adv_full_duplex = pAnInfo->RxConfig.D5_FD;
326             pAnInfo->mr_lp_adv_half_duplex = pAnInfo->RxConfig.D6_HD;
327             pAnInfo->mr_lp_adv_sym_pause = pAnInfo->RxConfig.D7_PS1;
328             pAnInfo->mr_lp_adv_asym_pause = pAnInfo->RxConfig.D8_PS2;
329             pAnInfo->mr_lp_adv_remote_fault1 = pAnInfo->RxConfig.D12_RF1;
330             pAnInfo->mr_lp_adv_remote_fault2 = pAnInfo->RxConfig.D13_RF2;
331             pAnInfo->mr_lp_adv_next_page = pAnInfo->RxConfig.D15_NP;
332
333             pAnInfo->LinkTime_us = pAnInfo->CurrentTime_us;
334
335             pAnInfo->mr_toggle_tx = !pAnInfo->mr_toggle_tx;
336             pAnInfo->mr_toggle_rx = pAnInfo->RxConfig.bits.D11;
337             pAnInfo->mr_np_rx = pAnInfo->RxConfig.D15_NP;
338             pAnInfo->mr_page_rx = AN_TRUE;
339
340             pAnInfo->State = AN_STATE_COMPLETE_ACK;
341             AnRet = AUTONEG_STATUS_TIMER_ENABLED;
342
343             break;
344
345         case AN_STATE_COMPLETE_ACK:
346             if(pAnInfo->AbilityMatch == AN_TRUE &&
347                 pAnInfo->RxConfig.AsUSHORT == 0)
348             {
349                 pAnInfo->State = AN_STATE_AN_ENABLE;
350                 break;
351             }
352
353             Delta_us = pAnInfo->CurrentTime_us - pAnInfo->LinkTime_us;
354
355             if(Delta_us > AN_LINK_TIMER_INTERVAL_US)
356             {
357                 if(pAnInfo->mr_adv_next_page == 0 ||
358                     pAnInfo->mr_lp_adv_next_page == 0)
359                 {
360                     pAnInfo->State = AN_STATE_IDLE_DETECT_INIT;
361                 }
362                 else
363                 {
364                     if(pAnInfo->TxConfig.bits.D15 == 0 &&
365                         pAnInfo->mr_np_rx == 0)
366                     {
367                         pAnInfo->State = AN_STATE_IDLE_DETECT_INIT;
368                     }
369                     else
370                     {
371                         AnRet = AUTONEG_STATUS_FAILED;
372                     }
373                 }
374             }
375
376             break;
377
378         case AN_STATE_IDLE_DETECT_INIT:
379             pAnInfo->LinkTime_us = pAnInfo->CurrentTime_us;
380
381             MM_AnTxIdle(pAnInfo);
382
383             pAnInfo->State = AN_STATE_IDLE_DETECT;
384
385             AnRet = AUTONEG_STATUS_TIMER_ENABLED;
386
387             break;
388
389         case AN_STATE_IDLE_DETECT:
390             if(pAnInfo->AbilityMatch == AN_TRUE &&
391                 pAnInfo->RxConfig.AsUSHORT == 0)
392             {
393                 pAnInfo->State = AN_STATE_AN_ENABLE;
394                 break;
395             }
396
397             Delta_us = pAnInfo->CurrentTime_us - pAnInfo->LinkTime_us;
398             if(Delta_us > AN_LINK_TIMER_INTERVAL_US)
399             {
400 #if 0
401 /*                if(pAnInfo->IdleMatch == AN_TRUE) */
402 /*                { */
403 #endif
404                     pAnInfo->State = AN_STATE_LINK_OK;
405 #if 0
406 /*                } */
407 /*                else */
408 /*                { */
409 /*                    AnRet = AUTONEG_STATUS_FAILED; */
410 /*                    break; */
411 /*                } */
412 #endif
413             }
414
415             break;
416
417         case AN_STATE_LINK_OK:
418             pAnInfo->mr_an_complete = AN_TRUE;
419             pAnInfo->mr_link_ok = AN_TRUE;
420             AnRet = AUTONEG_STATUS_DONE;
421
422             break;
423
424         case AN_STATE_NEXT_PAGE_WAIT_INIT:
425             break;
426
427         case AN_STATE_NEXT_PAGE_WAIT:
428             break;
429
430         default:
431             AnRet = AUTONEG_STATUS_FAILED;
432             break;
433     }
434
435     return AnRet;
436 }
437 #endif /* INCLUDE_TBI_SUPPORT */
438
439 #endif /* !defined(CONFIG_NET_MULTI) */