blob: 9023796aa05967f89891a9140998c746613e190a [file] [log] [blame]
wdenkfe8c2802002-11-03 00:38:21 +00001/******************************************************************************/
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
wdenkfe8c2802002-11-03 00:38:21 +000019/******************************************************************************/
20/* Description: */
21/* */
22/* Return: */
23/******************************************************************************/
24void
25MM_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
wdenkfe8c2802002-11-03 00:38:21 +000039/******************************************************************************/
40/* Description: */
41/* */
42/* Return: */
43/******************************************************************************/
44void
45MM_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
wdenkfe8c2802002-11-03 00:38:21 +000057/******************************************************************************/
58/* Description: */
59/* */
60/* Return: */
61/******************************************************************************/
62char
63MM_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 {
wdenk57b2d802003-06-27 21:31:46 +000078 Value32 = REG_RD(pDevice, MacCtrl.RxAutoNeg);
79 *pRxConfig = (unsigned short) Value32;
wdenkfe8c2802002-11-03 00:38:21 +000080
wdenk57b2d802003-06-27 21:31:46 +000081 Retcode = AN_TRUE;
wdenkfe8c2802002-11-03 00:38:21 +000082 }
83
84 return Retcode;
85}
86
87
wdenkfe8c2802002-11-03 00:38:21 +000088/******************************************************************************/
89/* Description: */
90/* */
91/* Return: */
92/******************************************************************************/
93void
94AutonegInit(
95 PAN_STATE_INFO pAnInfo)
96{
97 unsigned long j;
98
99 for(j = 0; j < sizeof(AN_STATE_INFO); j++)
100 {
wdenk57b2d802003-06-27 21:31:46 +0000101 ((unsigned char *) pAnInfo)[j] = 0;
wdenkfe8c2802002-11-03 00:38:21 +0000102 }
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
wdenkfe8c2802002-11-03 00:38:21 +0000112/******************************************************************************/
113/* Description: */
114/* */
115/* Return: */
116/******************************************************************************/
117AUTONEG_STATUS
118Autoneg8023z(
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 {
wdenk57b2d802003-06-27 21:31:46 +0000128 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;
wdenkfe8c2802002-11-03 00:38:21 +0000136 }
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 {
wdenk57b2d802003-06-27 21:31:46 +0000145 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 }
wdenkfe8c2802002-11-03 00:38:21 +0000160
wdenk57b2d802003-06-27 21:31:46 +0000161 if(RxConfig & AN_CONFIG_ACK)
162 {
163 pAnInfo->AckMatch = AN_TRUE;
164 }
165 else
166 {
167 pAnInfo->AckMatch = AN_FALSE;
168 }
wdenkfe8c2802002-11-03 00:38:21 +0000169
wdenk57b2d802003-06-27 21:31:46 +0000170 pAnInfo->IdleMatch = AN_FALSE;
wdenkfe8c2802002-11-03 00:38:21 +0000171 }
172 else
173 {
wdenk57b2d802003-06-27 21:31:46 +0000174 pAnInfo->IdleMatch = AN_TRUE;
wdenkfe8c2802002-11-03 00:38:21 +0000175
wdenk57b2d802003-06-27 21:31:46 +0000176 pAnInfo->AbilityMatchCfg = 0;
177 pAnInfo->AbilityMatchCnt = 0;
178 pAnInfo->AbilityMatch = AN_FALSE;
179 pAnInfo->AckMatch = AN_FALSE;
wdenkfe8c2802002-11-03 00:38:21 +0000180
wdenk57b2d802003-06-27 21:31:46 +0000181 RxConfig = 0;
wdenkfe8c2802002-11-03 00:38:21 +0000182 }
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 {
wdenk57b2d802003-06-27 21:31:46 +0000193 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 }
wdenkfe8c2802002-11-03 00:38:21 +0000199
wdenk57b2d802003-06-27 21:31:46 +0000200 /* Fall through.*/
wdenkfe8c2802002-11-03 00:38:21 +0000201
wdenk57b2d802003-06-27 21:31:46 +0000202 case AN_STATE_AN_ENABLE:
203 pAnInfo->mr_an_complete = AN_FALSE;
204 pAnInfo->mr_page_rx = AN_FALSE;
wdenkfe8c2802002-11-03 00:38:21 +0000205
wdenk57b2d802003-06-27 21:31:46 +0000206 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;
wdenkfe8c2802002-11-03 00:38:21 +0000214
wdenk57b2d802003-06-27 21:31:46 +0000215 pAnInfo->State = AN_STATE_AN_RESTART_INIT;
216 }
217 else
218 {
219 pAnInfo->State = AN_STATE_DISABLE_LINK_OK;
220 }
221 break;
wdenkfe8c2802002-11-03 00:38:21 +0000222
wdenk57b2d802003-06-27 21:31:46 +0000223 case AN_STATE_AN_RESTART_INIT:
224 pAnInfo->LinkTime_us = pAnInfo->CurrentTime_us;
225 pAnInfo->mr_np_loaded = AN_FALSE;
wdenkfe8c2802002-11-03 00:38:21 +0000226
wdenk57b2d802003-06-27 21:31:46 +0000227 pAnInfo->TxConfig.AsUSHORT = 0;
228 MM_AnTxConfig(pAnInfo);
wdenkfe8c2802002-11-03 00:38:21 +0000229
wdenk57b2d802003-06-27 21:31:46 +0000230 AnRet = AUTONEG_STATUS_TIMER_ENABLED;
wdenkfe8c2802002-11-03 00:38:21 +0000231
wdenk57b2d802003-06-27 21:31:46 +0000232 pAnInfo->State = AN_STATE_AN_RESTART;
wdenkfe8c2802002-11-03 00:38:21 +0000233
wdenk57b2d802003-06-27 21:31:46 +0000234 /* Fall through.*/
wdenkfe8c2802002-11-03 00:38:21 +0000235
wdenk57b2d802003-06-27 21:31:46 +0000236 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;
wdenkfe8c2802002-11-03 00:38:21 +0000249
wdenk57b2d802003-06-27 21:31:46 +0000250 case AN_STATE_DISABLE_LINK_OK:
251 AnRet = AUTONEG_STATUS_DONE;
252 break;
wdenkfe8c2802002-11-03 00:38:21 +0000253
wdenk57b2d802003-06-27 21:31:46 +0000254 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;
wdenkfe8c2802002-11-03 00:38:21 +0000258
wdenk57b2d802003-06-27 21:31:46 +0000259 /* 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;
wdenkfe8c2802002-11-03 00:38:21 +0000268
wdenk57b2d802003-06-27 21:31:46 +0000269 MM_AnTxConfig(pAnInfo);
wdenkfe8c2802002-11-03 00:38:21 +0000270
wdenk57b2d802003-06-27 21:31:46 +0000271 pAnInfo->State = AN_STATE_ABILITY_DETECT;
wdenkfe8c2802002-11-03 00:38:21 +0000272
wdenk57b2d802003-06-27 21:31:46 +0000273 break;
wdenkfe8c2802002-11-03 00:38:21 +0000274
wdenk57b2d802003-06-27 21:31:46 +0000275 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 }
wdenkfe8c2802002-11-03 00:38:21 +0000281
wdenk57b2d802003-06-27 21:31:46 +0000282 break;
wdenkfe8c2802002-11-03 00:38:21 +0000283
wdenk57b2d802003-06-27 21:31:46 +0000284 case AN_STATE_ACK_DETECT_INIT:
285 pAnInfo->TxConfig.D14_ACK = 1;
286 MM_AnTxConfig(pAnInfo);
wdenkfe8c2802002-11-03 00:38:21 +0000287
wdenk57b2d802003-06-27 21:31:46 +0000288 pAnInfo->State = AN_STATE_ACK_DETECT;
wdenkfe8c2802002-11-03 00:38:21 +0000289
wdenk57b2d802003-06-27 21:31:46 +0000290 /* Fall through. */
wdenkfe8c2802002-11-03 00:38:21 +0000291
wdenk57b2d802003-06-27 21:31:46 +0000292 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 }
wdenkfe8c2802002-11-03 00:38:21 +0000310
wdenk57b2d802003-06-27 21:31:46 +0000311 break;
wdenkfe8c2802002-11-03 00:38:21 +0000312
wdenk57b2d802003-06-27 21:31:46 +0000313 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 }
wdenkfe8c2802002-11-03 00:38:21 +0000323
wdenk57b2d802003-06-27 21:31:46 +0000324 /* 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;
wdenkfe8c2802002-11-03 00:38:21 +0000332
wdenk57b2d802003-06-27 21:31:46 +0000333 pAnInfo->LinkTime_us = pAnInfo->CurrentTime_us;
wdenkfe8c2802002-11-03 00:38:21 +0000334
wdenk57b2d802003-06-27 21:31:46 +0000335 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;
wdenkfe8c2802002-11-03 00:38:21 +0000339
wdenk57b2d802003-06-27 21:31:46 +0000340 pAnInfo->State = AN_STATE_COMPLETE_ACK;
341 AnRet = AUTONEG_STATUS_TIMER_ENABLED;
wdenkfe8c2802002-11-03 00:38:21 +0000342
wdenk57b2d802003-06-27 21:31:46 +0000343 break;
wdenkfe8c2802002-11-03 00:38:21 +0000344
wdenk57b2d802003-06-27 21:31:46 +0000345 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 }
wdenkfe8c2802002-11-03 00:38:21 +0000352
wdenk57b2d802003-06-27 21:31:46 +0000353 Delta_us = pAnInfo->CurrentTime_us - pAnInfo->LinkTime_us;
wdenkfe8c2802002-11-03 00:38:21 +0000354
wdenk57b2d802003-06-27 21:31:46 +0000355 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 }
wdenkfe8c2802002-11-03 00:38:21 +0000375
wdenk57b2d802003-06-27 21:31:46 +0000376 break;
wdenkfe8c2802002-11-03 00:38:21 +0000377
wdenk57b2d802003-06-27 21:31:46 +0000378 case AN_STATE_IDLE_DETECT_INIT:
379 pAnInfo->LinkTime_us = pAnInfo->CurrentTime_us;
wdenkfe8c2802002-11-03 00:38:21 +0000380
wdenk57b2d802003-06-27 21:31:46 +0000381 MM_AnTxIdle(pAnInfo);
wdenkfe8c2802002-11-03 00:38:21 +0000382
wdenk57b2d802003-06-27 21:31:46 +0000383 pAnInfo->State = AN_STATE_IDLE_DETECT;
wdenkfe8c2802002-11-03 00:38:21 +0000384
wdenk57b2d802003-06-27 21:31:46 +0000385 AnRet = AUTONEG_STATUS_TIMER_ENABLED;
wdenkfe8c2802002-11-03 00:38:21 +0000386
wdenk57b2d802003-06-27 21:31:46 +0000387 break;
wdenkfe8c2802002-11-03 00:38:21 +0000388
wdenk57b2d802003-06-27 21:31:46 +0000389 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 }
wdenkfe8c2802002-11-03 00:38:21 +0000396
wdenk57b2d802003-06-27 21:31:46 +0000397 Delta_us = pAnInfo->CurrentTime_us - pAnInfo->LinkTime_us;
398 if(Delta_us > AN_LINK_TIMER_INTERVAL_US)
399 {
wdenkfe8c2802002-11-03 00:38:21 +0000400#if 0
401/* if(pAnInfo->IdleMatch == AN_TRUE) */
402/* { */
403#endif
wdenk57b2d802003-06-27 21:31:46 +0000404 pAnInfo->State = AN_STATE_LINK_OK;
wdenkfe8c2802002-11-03 00:38:21 +0000405#if 0
406/* } */
407/* else */
408/* { */
409/* AnRet = AUTONEG_STATUS_FAILED; */
410/* break; */
411/* } */
412#endif
wdenk57b2d802003-06-27 21:31:46 +0000413 }
wdenkfe8c2802002-11-03 00:38:21 +0000414
wdenk57b2d802003-06-27 21:31:46 +0000415 break;
wdenkfe8c2802002-11-03 00:38:21 +0000416
wdenk57b2d802003-06-27 21:31:46 +0000417 case AN_STATE_LINK_OK:
418 pAnInfo->mr_an_complete = AN_TRUE;
419 pAnInfo->mr_link_ok = AN_TRUE;
420 AnRet = AUTONEG_STATUS_DONE;
wdenkfe8c2802002-11-03 00:38:21 +0000421
wdenk57b2d802003-06-27 21:31:46 +0000422 break;
wdenkfe8c2802002-11-03 00:38:21 +0000423
wdenk57b2d802003-06-27 21:31:46 +0000424 case AN_STATE_NEXT_PAGE_WAIT_INIT:
425 break;
wdenkfe8c2802002-11-03 00:38:21 +0000426
wdenk57b2d802003-06-27 21:31:46 +0000427 case AN_STATE_NEXT_PAGE_WAIT:
428 break;
wdenkfe8c2802002-11-03 00:38:21 +0000429
wdenk57b2d802003-06-27 21:31:46 +0000430 default:
431 AnRet = AUTONEG_STATUS_FAILED;
432 break;
wdenkfe8c2802002-11-03 00:38:21 +0000433 }
434
435 return AnRet;
436}
437#endif /* INCLUDE_TBI_SUPPORT */
438
439#endif /* !defined(CONFIG_NET_MULTI) */