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