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